552402 - Simple XY-Chartviewer

Multi channelgroup selection. Individual x-axis per channel.
Refactoring

Signed-off-by: Johannes Stamm <j.stamm@peak-solution.de>
diff --git a/org.eclipse.mdm.application/src/main/webapp/src/app/chartviewer/chart-viewer.style.css b/org.eclipse.mdm.application/src/main/webapp/src/app/chartviewer/chart-viewer.style.css
index 35fbfd6..364c1cb 100644
--- a/org.eclipse.mdm.application/src/main/webapp/src/app/chartviewer/chart-viewer.style.css
+++ b/org.eclipse.mdm.application/src/main/webapp/src/app/chartviewer/chart-viewer.style.css
@@ -20,10 +20,52 @@
   margin-bottom: 4px;

 }

 

-.toolbar .thin {

+.thin {

   padding: 4px;

 }

 

+.toggler {

+  text-align: right;

+  color: #6c757d;

+  cursor: pointer;

+}

+

+.toggler:hover {

+  color: black;

+}

+

+p-listbox >>> .ui-listbox-item {

+  padding: 4px 0 4px 8px !important;

+}

+

+p-listbox >>> p-header {

+  display: grid; 

+  grid-template-columns: 12% 63% 25%;

+  align-items: center;

+}

+

+p-listbox >>> .ui-listbox-header {

+  border-bottom-left-radius: 0;

+  border-bottom-right-radius: 0;

+  /* border-bottom-color: rgb(166,166,166); */

+}

+

+p-listbox >>> .ui-listbox-header-w-checkbox {

+  padding: 4px 8px;

+}

+

+.hiddenList >>> .ui-listbox-list-wrapper {

+  display: none;

+}

+

+.hiddenList >>> .ui-listbox-header-w-checkbox {

+  display: none;

+}

+

+p-listbox >>> .ypanel .ui-listbox-header-w-checkbox {

+  text-align: right;

+}

+

 p-togglebutton >>> .ui-button {

   font-size: 14px;

   margin: 0 3px;

@@ -54,6 +96,10 @@
   color: #6c757d!important;

 }

 

+p-spinner {

+  margin: 0 3px;

+}

+

 p-spinner >>> .ui-button {

   font-size: 14px;

   color: #6c757d;

@@ -66,4 +112,56 @@
   background-color:#c8c8c8;

   border-color:#c8c8c8;

   color:#333333;

+}

+

+p-spinner >>> .ui-spinner {

+  margin-top: -3px;

+}

+

+p-spinner >>> .ui-spinner-input {

+  height: 32px;

+}

+

+.hidden {

+  display: none;

+}

+

+.channelList {

+  list-style-type: none;

+  padding: 0;

+  margin-bottom: 0;

+  min-height: 80px;

+}

+

+.row {

+  display: grid;

+  grid-template-columns: 155px 185px;

+  align-items: center;

+  padding: 1px 8px 1px 8px;

+}

+

+p-panel >>> .ui-panel-content.ui-widget-content {

+  overflow-x: scroll;

+  overflow-y: visible;

+}

+

+p-panel >>> .ui-panel .ui-panel-titlebar {

+  background-color: inherit;

+  border-color: rgb(166,166,166);

+  padding: 6px 12px;

+}

+

+p-panel >>> .ui-panel .ui-panel-content {

+  border-color: rgb(166,166,166);

+  border-bottom-left-radius: 3px;

+  border-bottom-right-radius: 3px;

+  padding: 4px 10px

+}

+

+p-panel >>> .ui-inputtext {

+  padding: 2px 0.429em;

+}

+

+p-panel label {

+  font-weight: inherit;

 }
\ No newline at end of file
diff --git a/org.eclipse.mdm.application/src/main/webapp/src/app/chartviewer/chartviewer.module.ts b/org.eclipse.mdm.application/src/main/webapp/src/app/chartviewer/chartviewer.module.ts
index 2fcb508..03a4e8d 100644
--- a/org.eclipse.mdm.application/src/main/webapp/src/app/chartviewer/chartviewer.module.ts
+++ b/org.eclipse.mdm.application/src/main/webapp/src/app/chartviewer/chartviewer.module.ts
@@ -26,6 +26,8 @@
 import { ToggleButtonModule } from 'primeng/togglebutton';
 import { SpinnerModule } from 'primeng/spinner';
 import { MultiSelectModule } from 'primeng/multiselect';
+import { ListboxModule } from 'primeng/listbox';
+import { PanelModule } from 'primeng/panel';
 
 import { MDMCoreModule } from '../core/mdm-core.module';
 import { ChartViewerComponent } from './components/chartviewer/chart-viewer.component';
@@ -34,6 +36,8 @@
 import { XyChartViewerComponent } from './components/xy-chart-viewer/xy-chart-viewer.component';
 import { XyChartViewerNavCardComponent } from './components/xy-chart-viewer-nav-card/xy-chart-viewer-nav-card.component';
 import { RequestOptionsComponent } from './components/request-options/request-options.component';
+import { XyChartViewerToolbarComponent } from './components/xy-chart-viewer-toolbar/xy-chart-viewer-toolbar.component';
+import { XyChartDataSelectionPanelComponent } from './components/xy-chart-data-selection-panel/xy-chart-data-selection-panel.component';
 
 @NgModule({
   imports: [
@@ -49,7 +53,9 @@
     ChartModule,
     ToggleButtonModule,
     SpinnerModule,
-    MultiSelectModule
+    MultiSelectModule,
+    ListboxModule,
+    PanelModule
   ],
   declarations: [
     ChartViewerNavCardComponent,
@@ -58,6 +64,8 @@
     XyChartViewerComponent,
     XyChartViewerNavCardComponent,
     RequestOptionsComponent,
+    XyChartViewerToolbarComponent,
+    XyChartDataSelectionPanelComponent,
   ],
   exports: [
     ChartViewerNavCardComponent,
diff --git a/org.eclipse.mdm.application/src/main/webapp/src/app/chartviewer/components/request-options/request-options.component.html b/org.eclipse.mdm.application/src/main/webapp/src/app/chartviewer/components/request-options/request-options.component.html
index 8348eb8..108ee9a 100644
--- a/org.eclipse.mdm.application/src/main/webapp/src/app/chartviewer/components/request-options/request-options.component.html
+++ b/org.eclipse.mdm.application/src/main/webapp/src/app/chartviewer/components/request-options/request-options.component.html
@@ -1,3 +1,16 @@
+<!--********************************************************************************
+ * Copyright (c) 2015-2018 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************-->
 <p-accordion [style]="{'width':'100%'}">
   <p-accordionTab header="Optionen" [disabled]="!channelGroups || channelGroups.length === 0">
     <div class="p-grid nested-grid p-align-center">
diff --git a/org.eclipse.mdm.application/src/main/webapp/src/app/chartviewer/components/xy-chart-data-selection-panel/xy-chart-data-selection-panel.component.html b/org.eclipse.mdm.application/src/main/webapp/src/app/chartviewer/components/xy-chart-data-selection-panel/xy-chart-data-selection-panel.component.html
new file mode 100644
index 0000000..f64b5c1
--- /dev/null
+++ b/org.eclipse.mdm.application/src/main/webapp/src/app/chartviewer/components/xy-chart-data-selection-panel/xy-chart-data-selection-panel.component.html
@@ -0,0 +1,145 @@
+<!--********************************************************************************
+ * Copyright (c) 2015-2018 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************-->
+
+<div class="p-grid">
+  <div class="p-col-12" style="margin-top: 4px">
+    <p-listbox
+      [options]="channelGroups"
+      [(ngModel)]="selectedChannelGroups"
+      multiple="multiple"
+      checkbox="checkbox"
+      filter="filter"
+      optionLabel="name"
+      (onChange)="onSelectedChannelGroupsChanged($event)"
+      [ngClass]="{'hiddenList': hiddenGroups}"
+      [style]="{'width':'100%'}"
+      [listStyle]="{'height':'100px'}">
+      <p-header>
+          <span class="icon channelgroup"></span>
+          {{'SubMatrix' | mdmdatasourcetranslate}}
+          <span
+            class="fa toggler"
+            [ngClass]="{'fa-chevron-down': !hiddenGroups, 'fa-chevron-right': hiddenGroups}"
+            (click)="onToggleChannelGroupPanel($event)"></span>
+      </p-header>
+    </p-listbox>
+    <!-- <p-multiSelect
+      [style]="{'width':'100%'}"
+      defaultLabel="Choose ChannelGroups"
+      [options]="channelGroups"
+      [(ngModel)]="selectedChannelGroups"
+      optionLabel="name"
+      (onChange)="onSelectedChannelGroupsChanged($event)">
+    </p-multiSelect> -->
+  </div>
+  <div class="p-col-12">
+    <p-listbox [options]="yChannelOptions"
+      [(ngModel)]="selectedYChannels"
+      multiple="multiple"
+      checkbox="checkbox"
+      filter="filter"
+      optionLabel="name"
+      (onChange)="onSelectedYChannelsChanged($event)"
+      [ngClass]="{'hiddenList': hiddenYChannels}"
+      [style]="{'width':'100%'}"
+      [styleClass]="'ypanel'"
+      [listStyle]="{'height':'200px'}"
+      [showToggleAll]="false">
+      <p-header>
+        <span class="icon channel"></span>
+        Y-{{'MeaQuantity' | mdmdatasourcetranslate}}
+        <span
+        class="fa toggler"
+        [ngClass]="{'fa-chevron-down': !hiddenYChannels, 'fa-chevron-right': hiddenYChannels}"
+        (click)="onToggleYChannelPanel($event)"></span>
+      </p-header>
+    </p-listbox>
+    <!-- <p-multiSelect
+      [style]="{'width':'100%'}"
+      defaultLabel="Choose Channels"
+      [options]="yChannelOptions"
+      [(ngModel)]="selectedYChannels"
+      optionLabel="name"
+      (onChange)="onSelectedYChannelsChanged($event)"
+      [showToggleAll]="false">
+    </p-multiSelect> -->
+  </div>
+  <div class="p-col-12">
+    <p-panel
+      [toggleable]="true"
+      [collapsed]="true"
+      expandIcon="fa fa-chevron-right"
+      collapseIcon="fa fa-chevron-down">
+      <p-header>
+        <span class="icon channel"></span>
+        &nbsp;X-{{'MeaQuantity' | mdmdatasourcetranslate}}
+      </p-header>
+      <!-- <p-table [value]="selectedChannelRows">
+        <ng-template pTemplate="header">
+             <tr>
+                <th>Channel</th>
+                <th></th>
+            </tr>
+        </ng-template>
+        <ng-template pTemplate="body" let-rowData>
+            <tr>
+                <td>{{rowData.yChannel.name}}</td>
+                <td>
+                  <p-dropdown
+                    [style]="{'width':'100%'}"
+                    [options]="xChannelOptions[rowData.channelGroup.id]"
+                    [(ngModel)]="rowData.xChannel"
+                    placeholder="Select X"
+                    optionLabel="name"
+                    [showClear]="true"
+                    (onChange)="onSelectedXChannelChanged($event, rowData)">
+                  </p-dropdown>
+              </td>
+            </tr>
+        </ng-template>
+      </p-table> -->
+      <ul class="channelList">
+        <li *ngFor="let rowData of selectedChannelRows">
+          <div class="row">
+            <label>
+              {{rowData.yChannel.name}}
+            </label>
+            
+            <!-- appendTo="body" is workarround for overlay is hidden in panel. Problem: AppendTo body makes overly stuck on scroll -->
+            <p-dropdown
+              [(ngModel)]="rowData.xChannel"
+              [options]="xChannelOptions[rowData.channelGroup.id]"
+              appendTo="body"
+              [filter]="xChannelOptions[rowData.channelGroup.id]?.length > 5"
+              (onChange)="onSelectedXChannelChanged($event, rowData)"
+              placeholder="{{'chartviewer.xy-chart-data-selection-panel.select-channel-placeholder' | translate}}"
+              optionLabel="name"
+              [showClear]="false"
+              [style]="{'width':'95%'}">
+            </p-dropdown>
+          </div>
+        </li>
+      </ul>
+    </p-panel>
+    <!-- <p-dropdown
+      [style]="{'width':'100%'}"
+      [options]="xChannels"
+      [(ngModel)]="selectedXChannel"
+      placeholder="Select X"
+      optionLabel="name"
+      [showClear]="true"
+      (onChange)="onSelectedXChannelChanged($event)">
+    </p-dropdown>  -->
+  </div>
+</div>
\ No newline at end of file
diff --git a/org.eclipse.mdm.application/src/main/webapp/src/app/chartviewer/components/xy-chart-data-selection-panel/xy-chart-data-selection-panel.component.ts b/org.eclipse.mdm.application/src/main/webapp/src/app/chartviewer/components/xy-chart-data-selection-panel/xy-chart-data-selection-panel.component.ts
new file mode 100644
index 0000000..3465d68
--- /dev/null
+++ b/org.eclipse.mdm.application/src/main/webapp/src/app/chartviewer/components/xy-chart-data-selection-panel/xy-chart-data-selection-panel.component.ts
@@ -0,0 +1,472 @@
+/********************************************************************************
+ * Copyright (c) 2015-2018 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+import { Component, OnInit, Input, OnDestroy, EventEmitter, Output, OnChanges, SimpleChanges } from '@angular/core';
+import { ChannelSelectionRow, MeasuredValues} from '../../model/chartviewer.model';
+import { Subscription, of } from 'rxjs';
+import { ChartViewerDataService } from '../../services/chart-viewer-data.service';
+import { ChartViewerService } from '../../services/chart-viewer.service';
+import { ArrayUtilService } from 'src/app/core/services/array-util.service';
+import { MDMNotificationService } from 'src/app/core/mdm-notification.service';
+import { TYPE_MEASUREMENT, TYPE_CHANNELGROUP, TYPE_CHANNEL } from '../../model/constants';
+import { tap } from 'rxjs/operators';
+import { Node } from '../../../navigator/node';
+
+@Component({
+  selector: 'mdm5-xy-chart-data-selection-panel',
+  templateUrl: './xy-chart-data-selection-panel.component.html',
+  styleUrls: ['../../chart-viewer.style.css']
+})
+export class XyChartDataSelectionPanelComponent implements OnInit, OnDestroy, OnChanges {
+
+  @Input()
+  public channelGroups: Node[];
+  @Input()
+  public channels: Map<string, Node[]>;
+
+  @Input()
+  public xyMode: boolean;
+
+  @Output()
+  public onSelectionChanged = new EventEmitter<ChannelSelectionRow[]>();
+
+  // select options for channels
+  public yChannelOptions: Node[] = [];
+  public xChannelOptions: {[key: string]: Node[]} = {};
+
+  // channel(group) selection for chart
+  // !! change via setter to update cache for workarround !!
+  public selectedChannelGroups: Node[] = [];
+  public selectedYChannels: Node[] = [];
+
+  private xYcache = new Map<string, MeasuredValues[]>();
+  private selectionChanged = false;
+
+  // listbox workarround to determine toggled item(s)
+  private lastChannelGroupSelection: Node[] = [];
+  private lastYChannelSelection: Node[] = [];
+
+  public selectedChannelRows: ChannelSelectionRow[] = [];
+
+  // Toggle selection panel visibility
+  public hiddenGroups = false;
+  public hiddenYChannels = false;
+
+  // for x-channel default value
+  private independentChannels = new Map<string, Node>();
+
+  /********** subscriptions */
+  private chartViewerSub: Subscription;
+
+  constructor(private chartviewerDataService: ChartViewerDataService,
+              private chartViewerService: ChartViewerService,
+              private arrayUtil: ArrayUtilService,
+              private notificationService: MDMNotificationService) { }
+
+
+  /****************  Angular lifecycle-hooks ****************************/
+
+  ngOnInit() {
+    this.chartViewerSub = this.chartViewerService.onNodeMetaChange().subscribe(node => this.handleNodeSelectionInNavTree(node));
+  }
+
+  ngOnDestroy() {
+    this.chartViewerSub.unsubscribe();
+  }
+
+  ngOnChanges(changes: SimpleChanges) {
+    if (changes['xyMode']) {
+      this.reloadAxisSelectOptions().subscribe(() => {
+        if (this.selectionChanged) {
+          this.fireSelectionChanged();
+          this.selectionChanged = false;
+        }
+      });
+    }
+  }
+
+  /**************** Html-template listeners *****************************/
+
+   // x-axis
+   public onSelectedXChannelChanged(event: any) {
+    if (event.value == undefined) {
+      // work arround: if x-axis is deselected for an y-channel, plat over independent channel.
+      // should force selection on dropdown instead.
+      this.selectedChannelRows
+        .filter(row => row.xChannel == undefined)
+        .map(row => row.xChannel = this.independentChannels.get(row.channelGroup.id));
+    }
+    this.fireSelectionChanged();
+  }
+
+  // y-axis
+  public onSelectedYChannelsChanged(event: any) {
+    let channel: Node;
+    // Deselect
+    if (this.selectedYChannels.length < this.lastYChannelSelection.length) {
+      channel = this.lastYChannelSelection.find(yChannel => !this.selectedYChannels.some(c => yChannel.id === c.id));
+      // .forEach(yChannel => this.addOrRemoveRow(this.findChannelGroup(yChannel), yChannel));
+      // Select
+    } else {
+      channel = this.selectedYChannels.find(group => !this.lastYChannelSelection.some(g => group.id === g.id));
+    }
+    this.addOrRemoveRow(this.findChannelGroup(channel), channel);
+    this.lastYChannelSelection = this.selectedYChannels;
+    this.fireSelectionChanged();
+  }
+  //   // y-axis
+  //   public onSelectedYChannelsChanged(event: any) {
+  //     const yChannel = event.itemValue;
+  //     this.addOrRemoveRow(this.findChannelGroup(yChannel), );
+  //     this.fireSelectionChanged();
+  // }
+
+  // channelgroups
+  // public onSelectedChannelGroupsChanged(event: any) {
+  //     const item = event.itemValue;
+  //     // item is undefined, if select-all check box is clicked.
+  //     if (item == undefined) {
+  //       if (this.arrayUtil.isNotEmpty(this.selectedChannelGroups)) {
+  //         this.selectedChannelGroups.forEach(g => this.handleOnSelectChannelGroup(g));
+  //       } else {
+  //         this.resetChannelData();
+  //         this.fireSelectionChanged();
+  //       }
+  //     } else {
+  //       // item contains toggled channelGroup if single select box is clicked
+  //       this.handleOnSelectChannelGroup(item);
+  //     }
+  // }
+
+  public onSelectedChannelGroupsChanged(event: any) {
+    // All deselected
+    if (this.selectedChannelGroups.length === 0) {
+      this.resetChannelData();
+      this.fireSelectionChanged();
+    } else {
+      // Deselect
+      if (this.selectedChannelGroups.length < this.lastChannelGroupSelection.length) {
+        this.lastChannelGroupSelection
+        .filter(group => !this.selectedChannelGroups.some(g => group.id === g.id))
+        .forEach(group => this.handleDeselectChannelGroup(group));
+        // Select
+      } else {
+        this.selectedChannelGroups
+        .filter(group => !this.lastChannelGroupSelection.some(g => group.id === g.id))
+        .forEach(group => this.handleSelectChannelGroup(group));
+      }
+    }
+    this.lastChannelGroupSelection = this.selectedChannelGroups;
+  }
+
+  // private handleOnSelectChannelGroup(channelGroup: any) {
+  //   // the currently toggled group is selected (ngModel is updated faster then event.)
+  //   if (this.isNodeIn(channelGroup, this.selectedChannelGroups)) {
+  //     this.handleSelectChannelGroup(channelGroup);
+  //     // the currently toggled group is deselected
+  //   } else {
+  //     this.handleDeselectChannelGroup(channelGroup);
+  //   }
+  // }
+
+  public onToggleChannelGroupPanel(event: Event) {
+    this.hiddenGroups = !this.hiddenGroups;
+  }
+
+  public onToggleYChannelPanel(event: Event) {
+    this.hiddenYChannels = !this.hiddenYChannels;
+  }
+
+  private handleDeselectChannelGroup(channelGroup: Node) {
+    // remove rows
+    if (this.arrayUtil.isNotEmpty(this.selectedChannelRows)) {
+      this.selectedChannelRows = this.selectedChannelRows.filter(row => row.channelGroup.id !== channelGroup.id);
+    }
+    // remove selection
+    if (this.arrayUtil.isNotEmpty(this.selectedYChannels)) {
+      this.setSelectedYChannels(this.selectedYChannels.filter(channel =>
+        this.channels.get(channelGroup.id).findIndex(c => channel.id === c.id) === -1));
+    }
+    this.reloadAxisSelectOptions().subscribe(() => this.fireSelectionChanged());
+  }
+
+    /**
+   * Handle channelGroup selection via multiselect in html template
+   * @param channelGroup
+   */
+  private handleSelectChannelGroup(channelGroup: Node) {
+    const cached = this.xYcache.get(channelGroup.id);
+    if (cached != undefined) {
+      this.setChannelOptions(cached, channelGroup);
+      this.fireSelectionChanged();
+    } else {
+      this.chartviewerDataService.readAxisType(channelGroup)
+        .subscribe(mvls => {
+          this.setChannelOptions(mvls, channelGroup);
+          this.fireSelectionChanged();
+        });
+    }
+  }
+
+  private handleNodeSelectionInNavTree(node: Node) {
+    if (node != undefined) {
+      switch (node.type) {
+        case TYPE_MEASUREMENT:
+          this.xYcache.clear();
+          this.resetChannelData();
+          this.fireSelectionChanged();
+          break;
+        case TYPE_CHANNELGROUP:
+          this.cleanOldState();
+          this.addChannelGroupToSelection(node.id, node);
+          break;
+        case TYPE_CHANNEL:
+          this.cleanOldState();
+          // add related channel group to selection
+          if (this.arrayUtil.isNotEmpty(this.channelGroups) && this.channels != undefined) {
+            const channelGroup = this.findChannelGroup(node);
+            // this.addChannelGroupToSelection(channelGroupId, this.channelGroups.find(cg => cg.id === channelGroupId));
+            if (!this.isNodeIn(channelGroup, this.selectedChannelGroups)) {
+              this.setSelectedChannelGroups(this.selectedChannelGroups.concat([channelGroup]));
+              this.chartviewerDataService.readAxisType(channelGroup)
+              .subscribe(mvls => {
+                this.setChannelOptions(mvls, channelGroup);
+                this.addChannelToSelection(node, channelGroup);
+              });
+            } else {
+              // if channel is in axis type y, set as selected, if not selected already
+              this.addChannelToSelection(node, channelGroup);
+            }
+          }
+        break;
+      }
+    }
+  }
+
+    /**
+   * reset chart data, select options and selection, if selected channelgroups
+   * contain a channelGroup which does not belongto this measurement.
+   *
+   * notice: this works for channels aswell, since a channel cannot be selected without
+   * selecting the parent channelGroup aswell.
+   */
+  private cleanOldState() {
+    if (this.arrayUtil.isNotEmpty(this.selectedChannelGroups)
+      && this.selectedChannelGroups.some(selected => !this.isNodeIn(selected, this.channelGroups))) {
+      this.xYcache.clear();
+      this.resetChannelData();
+    }
+  }
+
+  /**
+   * Handle channel selection via nav-tree
+   * @param channel
+   * @param channelGroup
+   */
+  private addChannelToSelection(channel: Node, channelGroup: Node) {
+    // adds channel to selected y-channels if possible and creates row in table
+    if (this.isNodeIn(channel, this.yChannelOptions)) {
+      const index = this.selectedYChannels.findIndex(c => c.id === channel.id);
+      if (index === -1) {
+        this.setSelectedYChannels(this.selectedYChannels.concat([channel]));
+        this.addRow(channelGroup, channel);
+        this.fireSelectionChanged();
+      }
+    /**
+     *  @TODO -> expected behaviour on selecting x-channel in tree.
+     * suggestion: set it as x-channel for all selected y-channels of that channelgroup.
+     */
+    // if channel is of axis type x, set ... ?
+    } else if (this.isNodeIn(channel, this.xChannelOptions[channelGroup.id])) {
+      this.notificationService.notifyWarn('Selected X-Channel', 'Selected channel is of type x-axis. Change x/y mode.');
+    } else {
+      this.notificationService.notifyError('Unknown channel option', 'Not sure where you found this..');
+    }
+  }
+
+  /**
+   * Handle channelGroup selection via nav-tree
+   * @param id
+   * @param channelGroup
+   */
+  private addChannelGroupToSelection(id: string, channelGroup: Node) {
+    if (this.selectedChannelGroups == undefined) {
+      this.setSelectedChannelGroups([]);
+    }
+    if (!this.isNodeIn(channelGroup, this.selectedChannelGroups)) {
+      this.setSelectedChannelGroups(this.selectedChannelGroups.concat([channelGroup]));
+      this.handleSelectChannelGroup(channelGroup);
+    }
+  }
+
+  /**
+   * Adds options for x- and y-channels depending on given channelGroup
+   *
+   * @param measuredValues
+   * @param channelGroup
+   */
+  private setChannelOptions(measuredValues: MeasuredValues[], channelGroup: Node) {
+    if (channelGroup != undefined) {
+      // cache measuredValues to avoid reloading
+      this.xYcache.set(channelGroup.id, measuredValues);
+
+      // create empty array if property not exists
+      this.xChannelOptions[channelGroup.id] = this.xChannelOptions[channelGroup.id] || [];
+
+      if (this.xyMode) {
+        measuredValues.forEach(mvl => {
+          const tmpChannel = this.channels.get(channelGroup.id).filter(c => c.name === mvl.name)[0];
+          if (mvl.axisType === 'X_AXIS' || ( mvl.axisType == undefined && mvl.independent)) {
+            this.xChannelOptions[channelGroup.id] = this.xChannelOptions[channelGroup.id].concat(tmpChannel);
+            // cache independent channels for default x-axis.
+            if (mvl.independent) {
+              this.independentChannels.set(channelGroup.id, tmpChannel);
+            }
+          } else if (mvl.axisType === 'Y_AXIS') {
+            this.yChannelOptions = this.yChannelOptions.concat(tmpChannel);
+          }
+        });
+      } else {
+        // cache independent channel for default x-axis.
+        const value = measuredValues.find(mvl => mvl.independent);
+        const tmpChannel = this.channels.get(channelGroup.id).filter(c => c.name === value.name)[0];
+        this.independentChannels.set(channelGroup.id, tmpChannel);
+
+        const tmpChannels = this.channels.get(channelGroup.id);
+        this.xChannelOptions[channelGroup.id] = this.xChannelOptions[channelGroup.id].concat(tmpChannels);
+        this.yChannelOptions = this.yChannelOptions.concat(tmpChannels);
+      }
+    }
+  }
+
+  /**
+   * Resets selections and select options to empty state.
+   */
+  private resetChannelData() {
+    this.setSelectedChannelGroups([]);
+    this.selectedChannelRows = [];
+    this.setSelectedYChannels([]);
+    this.channelGroups = [].concat(this.channelGroups);
+    this.xChannelOptions = {};
+    this.yChannelOptions = [];
+  }
+
+  // /**
+  //  * Reloads the select options for the x- and y-axis dropdowns
+  //  */
+  // private reloadAxisSelectOptions() {
+  //   this.xChannelOptions = {};
+  //   this.yChannelOptions = [];
+  //   if (this.arrayUtil.isNotEmpty(this.selectedChannelGroups)) {
+  //     const uncached = this.selectedChannelGroups.filter(g => this.xYcache.get(g.id) === undefined);
+  //     const cached = this.selectedChannelGroups.filter(g => this.xYcache.get(g.id) !== undefined);
+
+  //     const obs = uncached.map(cg => this.chartviewerDataService.readAxisType(cg));
+  //     return forkJoin(
+  //         forkJoin(obs)
+  //           .pipe(tap(array => array.forEach((mvls, index) => this.setChannelOptions(mvls, uncached[index])))),
+  //         of(cached.map((group, index) => this.setChannelOptions(this.xYcache.get(group.id), cached[index]))))
+  //       .pipe(tap(() => this.removeSelectionsNotMatchingXYMode()));
+  //   }
+  //   return of();
+  // }
+
+    /**
+   * Reloads the select options for the x- and y-axis dropdowns
+   */
+  private reloadAxisSelectOptions() {
+    this.xChannelOptions = {};
+    this.yChannelOptions = [];
+    if (this.arrayUtil.isNotEmpty(this.selectedChannelGroups)) {
+      const cached = this.selectedChannelGroups.filter(g => this.xYcache.get(g.id) !== undefined);
+      return of(cached.map((group, index) => this.setChannelOptions(this.xYcache.get(group.id), cached[index])))
+              .pipe(tap(() => this.removeSelectionsNotMatchingXYMode()));
+    }
+    return of();
+  }
+
+  private removeSelectionsNotMatchingXYMode() {
+    if (this.selectedYChannels.length > 0) {
+      const l = this.selectedChannelRows.length;
+      this.selectedChannelRows = this.selectedChannelRows.filter(row => this.isNodeIn(row.yChannel, this.yChannelOptions));
+      this.setSelectedYChannels(this.selectedYChannels.filter(channel => this.isNodeIn(channel, this.yChannelOptions)));
+      this.selectionChanged = l !== this.selectedChannelRows.length;
+    }
+  }
+
+   /**
+   * Row control for table with x-channel selection.
+   *
+   * @param channelGroup
+   * @param yChannel
+   */
+  private addOrRemoveRow(channelGroup: Node, yChannel: Node) {
+    const index = this.selectedChannelRows.findIndex(row => row.yChannel.id === yChannel.id);
+    if (index > -1) {
+      this.selectedChannelRows.splice(index, 1);
+      this.selectedChannelRows = [].concat(this.selectedChannelRows);
+    } else {
+      this.addRow(channelGroup, yChannel);
+    }
+  }
+
+  /**
+   * Add row to selection
+   * @param channelGroup
+   * @param yChannel
+   */
+  private addRow(channelGroup: Node, yChannel: Node) {
+    const row = new ChannelSelectionRow(channelGroup, yChannel, this.independentChannels.get(channelGroup.id));
+    this.selectedChannelRows.push(row);
+  }
+
+   /**
+   * Returns true if node with given id is in the given array.
+   *
+   * @param array the array
+   * @param id the id
+   */
+  private isNodeIn(node: Node, array: Node[]) {
+    let response = false;
+    if (node != undefined && this.arrayUtil.isNotEmpty(array)) {
+      response = array.findIndex(n => n.id === node.id) > -1;
+    }
+    return response;
+  }
+
+  /**
+   * Looks up parent channelGroup for channel via the channel map.
+   *
+   * @param channel
+   */
+  private findChannelGroup(channel: Node) {
+    const channelGroupId = Array.from(this.channels.keys())
+            .find(key => this.isNodeIn(channel, this.channels.get(key)));
+    return this.channelGroups.find(cg => cg.id === channelGroupId);
+  }
+
+  private fireSelectionChanged() {
+    this.onSelectionChanged.emit(this.selectedChannelRows);
+  }
+
+  private setSelectedYChannels(channels: Node[]) {
+    this.selectedYChannels = channels;
+    this.lastYChannelSelection = channels;
+  }
+
+  private setSelectedChannelGroups(channelGroups: Node[]) {
+    this.selectedChannelGroups = channelGroups;
+    this.lastChannelGroupSelection = channelGroups;
+  }
+}
diff --git a/org.eclipse.mdm.application/src/main/webapp/src/app/chartviewer/components/xy-chart-viewer-nav-card/xy-chart-viewer-nav-card.component.html b/org.eclipse.mdm.application/src/main/webapp/src/app/chartviewer/components/xy-chart-viewer-nav-card/xy-chart-viewer-nav-card.component.html
index e23db48..01b2142 100644
--- a/org.eclipse.mdm.application/src/main/webapp/src/app/chartviewer/components/xy-chart-viewer-nav-card/xy-chart-viewer-nav-card.component.html
+++ b/org.eclipse.mdm.application/src/main/webapp/src/app/chartviewer/components/xy-chart-viewer-nav-card/xy-chart-viewer-nav-card.component.html
@@ -13,10 +13,11 @@
  ********************************************************************************-->
 
 <div *ngIf="measurement === undefined || channelGroups === undefined || channels === undefined">
-  No Node selected.
-  <button (click)="onClick()">Click</button>
+  <div class="alert alert-info" style="margin: 0;">
+    <strong>{{'chartviewer.xy-chart-viewer-nav-card.no-node-selected' | translate}}</strong>
+  </div>
 </div>
 
 <div *ngIf="measurement !== undefined && channelGroups !== undefined && channels !== undefined">
-  <app-xy-chart-viewer [measurement]="measurement" [channelGroups]="channelGroups" [channels]="channels"></app-xy-chart-viewer>
+  <app-xy-chart-viewer [channelGroups]="channelGroups" [channels]="channels"></app-xy-chart-viewer>
 </div>
\ No newline at end of file
diff --git a/org.eclipse.mdm.application/src/main/webapp/src/app/chartviewer/components/xy-chart-viewer-nav-card/xy-chart-viewer-nav-card.component.ts b/org.eclipse.mdm.application/src/main/webapp/src/app/chartviewer/components/xy-chart-viewer-nav-card/xy-chart-viewer-nav-card.component.ts
index 06b030b..af4d82d 100644
--- a/org.eclipse.mdm.application/src/main/webapp/src/app/chartviewer/components/xy-chart-viewer-nav-card/xy-chart-viewer-nav-card.component.ts
+++ b/org.eclipse.mdm.application/src/main/webapp/src/app/chartviewer/components/xy-chart-viewer-nav-card/xy-chart-viewer-nav-card.component.ts
@@ -17,12 +17,11 @@
 import { MDMNotificationService } from 'src/app/core/mdm-notification.service';
 import { Node } from '../../../navigator/node';
 import { TYPE_CHANNEL, TYPE_CHANNELGROUP, TYPE_MEASUREMENT } from '../../model/constants';
-import { Subscription, concat, forkJoin, zip, of } from 'rxjs';
+import { Subscription, forkJoin } from 'rxjs';
 import { NodeService } from 'src/app/navigator/node.service';
-import { map, flatMap, tap } from 'rxjs/operators';
+import { map, tap } from 'rxjs/operators';
 import { MDMItem } from 'src/app/core/mdm-item';
 import { ChartViewerService } from '../../services/chart-viewer.service';
-import { ArrayUtilService } from 'src/app/core/services/array-util.service';
 
 @Component({
   selector: 'app-xy-chart-viewer-nav-card',
@@ -34,9 +33,10 @@
   public channelGroups: Node[];
   public measurement: Node;
 
+  private selectedNode: Node;
+
   // Subscriptions
   private selectedNodeSub: Subscription;
-  private selectedNode: Node;
 
   constructor(
     private navigatorService: NavigatorService,
@@ -57,14 +57,6 @@
   }
 
   /**
-  * @TODO remove
-  */
- onClick() {
-   const item = new MDMItem('MDMCRASH', 'Measurement', '180');
-   setTimeout(() => this.navigatorService.fireOnOpenInTree([item]));
- }
-
-  /**
    * Handle node selection in navigation tree.
    * Loads necessary data for xy chart, if not present:
    *  - Measurement:
@@ -105,7 +97,7 @@
   }
 
   private selectedChannelGroup(node: Node) {
-    if (this.isChannelGroupPresent(node)) {
+    if (!this.isChannelGroupPresent(node)) {
       this.loadMeasurement(node);
     } else {
       this.chartViewerService.sendNodeMeta(this.selectedNode);
@@ -170,58 +162,14 @@
         });
   }
 
-  // private load(node: Node) {
-  //   this.searchNodes(node, TYPE_MEASUREMENT)
-  //   .pipe(
-  //     /** @TODO in general true? */
-  //     // parent measurement must be distinct
-  //     map(measurements => measurements[0]),
-  //     tap(measurement => this.measurement = measurement),
-  //     flatMap(measurement => this.searchNodes(measurement, TYPE_CHANNELGROUP)),
-  //     tap(channelGroups => this.channelGroups = channelGroups),
-  //     flatMap(channelGroups => forkJoin(channelGroups.map(channelGroup => this.searchNodes(channelGroup, TYPE_CHANNEL)))),
-  //     map(n => n.map((x, i) => ({group: channelGroups[i], channels: x})))
-
-  //   ).subscribe(measurement => {
-  //     this.measurement = measurement;
-  //     this.loadChannelGroups(this.measurement);
-  //   });
-  // }
-
   private loadChannels(channelGroups: Node[]) {
+    this.channels.clear();
     let obsArray = channelGroups.map(channelGroup => this.searchNodes(channelGroup, TYPE_CHANNEL));
     forkJoin(obsArray).pipe(
         tap(array => array.forEach((channels, index) => this.channels.set(channelGroups[index].id, channels)))
       ).subscribe(datasets => this.chartViewerService.sendNodeMeta(this.selectedNode));
-
-    // forkJoin(obsArray).pipe(
-    //   map(n => n.map((x, i) => ({group: channelGroups[i], channels: x})))
-    //     ).subscribe(datasets => {
-    //       datasets.forEach(data => this.channels.set(data.group.id, data.channels));
-    //       this.chartViewerService.sendNodeMeta(this.selectedNode);
-    //     }
-    // );
-
-    // forkJoin(obsArray)
-    //   .pipe(
-    //     flatMap(channelsArray => zip(channelGroups, channelsArray))
-    //   )
-    //   .subscribe(([cg, channels]) => {
-    //     console.log('everevver???');
-    //     console.log(cg);
-    //     console.log(channels)
-    //     this.channels.set(cg.id, channels)});
-    // return forkJoin(channelGroups.map(channelGroup => this.searchNodes(channelGroup, TYPE_CHANNEL)));
   }
 
-
-  // private loadChannels2(channelGroups: Node[]) {
-  //   channelGroups.forEach(channelGroup =>
-  //     this.searchNodes(channelGroup, TYPE_CHANNEL)
-  //       .subscribe(channels => this.channels.set(channelGroup.id, channels))
-  //   );
-  // }
-
   private searchNodes(node: Node, targetType: string) {
     const filter = 'filter=' + node.type + '.Id eq \"' + node.id + '\"';
     return this.nodeService.searchNodes(filter, node.sourceName, targetType);
diff --git a/org.eclipse.mdm.application/src/main/webapp/src/app/chartviewer/components/xy-chart-viewer-toolbar/xy-chart-viewer-toolbar.component.html b/org.eclipse.mdm.application/src/main/webapp/src/app/chartviewer/components/xy-chart-viewer-toolbar/xy-chart-viewer-toolbar.component.html
new file mode 100644
index 0000000..bb0d753
--- /dev/null
+++ b/org.eclipse.mdm.application/src/main/webapp/src/app/chartviewer/components/xy-chart-viewer-toolbar/xy-chart-viewer-toolbar.component.html
@@ -0,0 +1,101 @@
+<!--********************************************************************************
+ * Copyright (c) 2015-2018 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************-->
+<div class="p-col-12 thin" >
+  <!-- ChannelSelection -->
+  <p-toggleButton
+    [(ngModel)]="properties.showSelection"
+    [onIcon]="'fa fa-columns'"
+    offIcon="fa fa-square-o"
+    onLabel=""
+    offLabel=""
+    (onChange)="onChangeProperty($event)"
+    title="{{(properties.showSelection ? 'chartviewer.xy-chart-viewer-toolbar.hide-data-selection-panel' : 'chartviewer.xy-chart-viewer-toolbar.show-data-selection-panel')| translate }}">
+  </p-toggleButton>
+  <!-- X/Y-mode -->
+  <p-toggleButton
+    [(ngModel)]="xyMode"
+    [onIcon]="'fa fa-filter'"
+    offIcon="fa fa-filter"
+    onLabel=""
+    offLabel=""
+    (onChange)="onToggleXyMode($event)"
+    title="{{(xyMode ? 'chartviewer.xy-chart-viewer-toolbar.deactivate-xy-mode' : 'chartviewer.xy-chart-viewer-toolbar.activate-xy-mode')| translate }}">
+  </p-toggleButton>
+  <span style="width:12px; display:inline-block;"></span>
+  <!-- Legend -->
+  <p-toggleButton
+    [onIcon]="'fa fa-map'"
+    offIcon="fa fa-map-o"
+    onLabel=""
+    offLabel=""
+    [(ngModel)]="properties.options.legend.display"
+    (onChange)="onChangeProperty($event)"
+    title="{{(properties?.options?.legend?.display ? 'chartviewer.xy-chart-viewer-toolbar.hide-chart-legend' : 'chartviewer.xy-chart-viewer-toolbar.show-chart-legend')| translate }}">
+  </p-toggleButton>
+  <!-- Linewidth -->
+  <p-spinner
+    [(ngModel)]="properties.lineWidth"
+    [min]="0.25"
+    [step]="0.25"
+    size="1"
+    (onChange)="onChangeProperty($event)"
+    title="{{'chartviewer.xy-chart-viewer-toolbar.line-width' | translate }}">
+  </p-spinner>
+  <!-- draw lines -->
+  <p-toggleButton
+    [onIcon]="'fa fa-line-chart'"
+    offIcon="fa fa-line-chart"
+    onLabel=""
+    offLabel=""
+    [(ngModel)]="properties.showLines"
+    (onChange)="onToggleShowLines($event)"
+    title="{{(properties.showLines ? 'chartviewer.xy-chart-viewer-toolbar.hide-lines' : 'chartviewer.xy-chart-viewer-toolbar.show-lines')| translate }}">
+  </p-toggleButton>
+  <!-- fill area -->
+  <p-toggleButton
+    [onIcon]="'fa fa-area-chart'"
+    offIcon="fa fa-area-chart"
+    onLabel=""
+    offLabel=""
+    [(ngModel)]="properties.fillArea"
+    (onChange)="onChangeProperty($event)"
+    [disabled]="!properties.showLines"
+    title="{{(properties.fillArea ? 'chartviewer.xy-chart-viewer-toolbar.clear-area' : 'chartviewer.xy-chart-viewer-toolbar.fill-area')| translate }}">
+  </p-toggleButton>
+  <!-- Datapoints -->
+  <p-toggleButton
+    title="Show Datapoints"
+    [onIcon]="'fa fa-share-alt'"
+    offIcon="fa fa-share-alt"
+    onLabel=""
+    offLabel=""
+    [(ngModel)]="properties.drawPoints"
+    (onChange)="onChangeProperty($event)"
+    title="{{(properties.drawPoints ? 'chartviewer.xy-chart-viewer-toolbar.hide-datapoints' : 'chartviewer.xy-chart-viewer-toolbar.show-datapoints'| translate) }}">
+  </p-toggleButton>
+  <!-- tension -->
+  <p-spinner
+    size="1"
+    [(ngModel)]="properties.lineTension"
+    [min]="0"
+    [step]="0.1"
+    [max]="1"
+    (onChange)="onChangeProperty($event)"
+    title="{{'chartviewer.xy-chart-viewer-toolbar.tension' | translate }}">
+  </p-spinner>
+  
+<!-- <div class="ui-g-12 ui-md-2">
+  <p-button label="Reset" (onClick)="onResetZoom()"></p-button>
+</div> -->
+</div>
\ No newline at end of file
diff --git a/org.eclipse.mdm.application/src/main/webapp/src/app/chartviewer/components/xy-chart-viewer-toolbar/xy-chart-viewer-toolbar.component.ts b/org.eclipse.mdm.application/src/main/webapp/src/app/chartviewer/components/xy-chart-viewer-toolbar/xy-chart-viewer-toolbar.component.ts
new file mode 100644
index 0000000..b22f402
--- /dev/null
+++ b/org.eclipse.mdm.application/src/main/webapp/src/app/chartviewer/components/xy-chart-viewer-toolbar/xy-chart-viewer-toolbar.component.ts
@@ -0,0 +1,82 @@
+/********************************************************************************
+ * Copyright (c) 2015-2018 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
+import { ChartToolbarProperties } from '../../model/chartviewer.model';
+
+@Component({
+  selector: 'mdm5-xy-chart-viewer-toolbar',
+  templateUrl: './xy-chart-viewer-toolbar.component.html',
+  styleUrls: ['../../chart-viewer.style.css']
+})
+export class XyChartViewerToolbarComponent implements OnInit {
+
+  @Output()
+  public xyModeChanged = new EventEmitter<boolean>();
+  @Output()
+  public toolbarPropertiesChanged = new EventEmitter<ChartToolbarProperties>();
+
+  // if true, x- and y-channels have to be channels with axisType 'X_AXIS', or 'Y_AXIS' respectively.
+  // change xy requires reloading of select options. Thus requires own event.
+  public xyMode = true;
+  // holds actual properties
+  public properties = new ChartToolbarProperties();
+  // model for showlines.
+  public showLegend = true;
+
+  constructor() { }
+
+  ngOnInit() {
+
+    /** properties for cahrt elements */
+
+    // if true, shows pannel with channel(-group) selection
+    this.properties.showSelection = true;
+    // if true, draws datapoints
+    this.properties.drawPoints = false;
+    // the charts borderwidth (width of lines, border for points)
+    this.properties.lineWidth = 1;
+    // if true, draws lines connecting datapoints
+    this.properties.showLines = true;
+    // if true, fills are below graph
+    this.properties.fillArea = false;
+    // the interpolation degree. 0 = linear, 0.4 = Bezier
+    this.properties.lineTension = 0;
+
+    // /** properties directly passed to cahrt options */
+    // if legend.display true, shows chart legend
+    this.properties.options = {legend: {display: true}};
+
+    // emit to send initial properties to chart viewer
+    this.xyModeChanged.emit(this.xyMode);
+    this.toolbarPropertiesChanged.emit(this.properties);
+  }
+
+  // X- and y-axis options are determined by channels axis type, if xyMode toggled to true
+  public onToggleXyMode(event: Event) {
+    this.xyModeChanged.emit(this.xyMode);
+  }
+
+  public onChangeProperty(event: Event) {
+    this.toolbarPropertiesChanged.emit(this.properties);
+  }
+
+  // displays/hides lines connecting data points
+  public onToggleShowLines(event: Event) {
+    if (!this.properties.showLines) {
+      this.properties.fillArea = false;
+    }
+    this.toolbarPropertiesChanged.emit(this.properties);
+  }
+}
diff --git a/org.eclipse.mdm.application/src/main/webapp/src/app/chartviewer/components/xy-chart-viewer/xy-chart-viewer.component.html b/org.eclipse.mdm.application/src/main/webapp/src/app/chartviewer/components/xy-chart-viewer/xy-chart-viewer.component.html
index 191b87e..e689d0b 100644
--- a/org.eclipse.mdm.application/src/main/webapp/src/app/chartviewer/components/xy-chart-viewer/xy-chart-viewer.component.html
+++ b/org.eclipse.mdm.application/src/main/webapp/src/app/chartviewer/components/xy-chart-viewer/xy-chart-viewer.component.html
@@ -1,59 +1,21 @@
+<!--********************************************************************************
+ * Copyright (c) 2015-2018 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************-->
 <div class="p-grid toolbar">
-  <!-- Toolbar -->
-  <div class="p-col-12 thin" >
-    <!-- ChannelSelection -->
-    <p-toggleButton
-      [(ngModel)]="showSelection"
-      [onIcon]="'fa fa-columns'"
-      offIcon="fa fa-square-o"
-      onLabel=""
-      offLabel="">
-    </p-toggleButton>
-    <span style="width:4px; display:inline-block;"></span>
-    <!-- X/Y-mode -->
-    <p-toggleButton
-      [(ngModel)]="xyMode"
-      onLabel="X/Y"
-      offLabel="All"
-      (onChange)="onToggleXyMode($event)">
-    </p-toggleButton>
-    <span style="width:4px; display:inline-block;"></span>
-    <!-- Legend -->
-    <p-toggleButton
-      title="Show legend"
-      [onIcon]="'fa fa-map'"
-      offIcon="fa fa-map-o"
-      onLabel=""
-      offLabel=""
-      [(ngModel)]="showLegend"
-      (onChange)="onToggleLegend($event)">
-    </p-toggleButton>
-    <span style="width:4px; display:inline-block;"></span>
-    <!-- Linewidth -->
-    <p-spinner
-      size="1"
-      [(ngModel)]="lineWidth"
-      title="Line width"
-      [min]="0.25"
-      [step]="0.25"
-      (onChange)="onChangeLineWidth($event)">
-    </p-spinner>
-    <span style="width:4px; display:inline-block;"></span>
-    <!-- Datapoints -->
-    <p-toggleButton
-      title="Show Datapoints"
-      [onIcon]="'fa fa-share-alt'"
-      offIcon="fa fa-share-alt"
-      onLabel=""
-      offLabel=""
-      [(ngModel)]="drawPoints"
-      (onChange)="onToggleDrawPoints($event)">
-    </p-toggleButton>
-    
-  <!-- <div class="ui-g-12 ui-md-2">
-    <p-button label="Reset" (onClick)="onResetZoom()"></p-button>
-  </div> -->
-  </div>
+  <mdm5-xy-chart-viewer-toolbar #toolbar
+    (xyModeChanged)="onXyModeChanged($event)"
+    (toolbarPropertiesChanged)="onToolbarPropertiesChanged($event)">
+  </mdm5-xy-chart-viewer-toolbar>
 </div>
 
   <!-- <ng-template let-dataset pTemplate="item">
@@ -63,51 +25,22 @@
 <!-- View area -->
 <div class="p-grid nested-grid">
   <!-- Axis selection -->
-  <div *ngIf="showSelection" class="p-col-3">
-    <div class="p-grid">
-      <div class="p-col-12" style="margin-top: 4px">
-        <p-multiSelect
-          [style]="{'width':'100%'}"
-          defaultLabel="Choose ChannelGroups"
-          [options]="channelGroups"
-          [(ngModel)]="selectedChannelGroups"
-          optionLabel="name"
-          (onChange)="onSelectedChannelGroupsChanged($event)">
-        </p-multiSelect>
-      </div>
-      <div class="p-col-12">
-        <p-multiSelect
-          [style]="{'width':'100%'}"
-          defaultLabel="Choose Channels"
-          [options]="yChannels"
-          [(ngModel)]="selectedYChannels"
-          optionLabel="name"
-          (onChange)="onSelectedYChannelsChanged($event)"
-          [virtualScroll]="true"
-          [itemSize]="34">
-        </p-multiSelect>  
-      </div>
-      <div class="p-col-12">
-        <p-dropdown
-          [style]="{'width':'100%'}"
-          [options]="xChannels"
-          [(ngModel)]="selectedXChannel"
-          placeholder="Select X"
-          optionLabel="name"
-          [showClear]="true"
-          (onChange)="onSelectedXChannelChanged($event)">
-        </p-dropdown> 
-      </div>
-    </div>
+  <div [ngClass]="showSelection ? 'p-col-3' : 'hidden'">
+    <mdm5-xy-chart-data-selection-panel
+      [channelGroups]="channelGroups"
+      [channels]="channels"
+      [xyMode]="xyMode"
+      (onSelectionChanged)="onDataSelectionChanged($event)"
+    ></mdm5-xy-chart-data-selection-panel>
   </div>
   <!-- Chart / Table -->
   <div [ngClass]="showSelection ? 'p-col-9' : 'p-col-12'">
-      <p-chart #xyChart type="scatter" [data]="data" [options]="options"></p-chart>
+    <p-chart #xyChart type="scatter" [data]="data"></p-chart>
   </div>
 </div>
 <div class="p-grid">
   <div class="p-col-12">
-    <mdm5-request-options [channelGroups]="selectedChannelGroups" (onRequestOptionsChanged)="onRequestOptionsChanged($event)"></mdm5-request-options>
+    <mdm5-request-options [channelGroups]="channelGroups" (onRequestOptionsChanged)="onRequestOptionsChanged($event)"></mdm5-request-options>
   </div>
 </div>
 
diff --git a/org.eclipse.mdm.application/src/main/webapp/src/app/chartviewer/components/xy-chart-viewer/xy-chart-viewer.component.ts b/org.eclipse.mdm.application/src/main/webapp/src/app/chartviewer/components/xy-chart-viewer/xy-chart-viewer.component.ts
index 96d4142..f25438e 100644
--- a/org.eclipse.mdm.application/src/main/webapp/src/app/chartviewer/components/xy-chart-viewer/xy-chart-viewer.component.ts
+++ b/org.eclipse.mdm.application/src/main/webapp/src/app/chartviewer/components/xy-chart-viewer/xy-chart-viewer.component.ts
@@ -12,412 +12,189 @@
  *
  ********************************************************************************/
 
-import { Component, OnInit, Input, ViewChild, OnDestroy } from '@angular/core';
+import { Component, OnInit, Input, ViewChild } from '@angular/core';
 
 import { UIChart } from 'primeng/chart';
-import { map, tap, reduce } from 'rxjs/operators';
+import { map, flatMap } from 'rxjs/operators';
 
 import { Node } from '../../../navigator/node';
 
-import { ChartData, ChartDataSet, MeasuredValues, RequestOptions, ChartXyDataSet } from '../../model/chartviewer.model';
-import { ChartViewerDataService, getDataArray } from '../../services/chart-viewer-data.service';
-import { TYPE_CHANNEL, TYPE_CHANNELGROUP, TYPE_MEASUREMENT } from '../../model/constants';
+import { ChartData, ChartDataSet, MeasuredValues, RequestOptions, ChannelSelectionRow,
+         ChartXyDataSet, ChartToolbarProperties} from '../../model/chartviewer.model';
+import { ChartViewerDataService } from '../../services/chart-viewer-data.service';
 import { ArrayUtilService } from 'src/app/core/services/array-util.service';
 import { ChartViewerService } from '../../services/chart-viewer.service';
-import { Subscription, forkJoin, zip, of } from 'rxjs';
+import { forkJoin} from 'rxjs';
+import { MDMNotificationService } from 'src/app/core/mdm-notification.service';
 
 @Component({
   selector: 'app-xy-chart-viewer',
   templateUrl: './xy-chart-viewer.component.html',
   styleUrls: ['../../chart-viewer.style.css']
 })
-export class XyChartViewerComponent implements OnInit, OnDestroy {
+export class XyChartViewerComponent implements OnInit {
 
   @ViewChild('xyChart')
   public chart: UIChart;
 
-  /** measurement and all available channels / channelgroups for that measurement
-   * based on node selection in navigation tree. Is managed by "parent" component
-   * to avoid unnecessary reloads.
-   */
-  @Input()
-  public measurement: Node;
   @Input()
   public channelGroups: Node[];
   @Input()
   public channels: Map<string, Node[]>;
 
-  // options for channels
-  public xChannels: Node[] = [];
-  public yChannels: Node[] = [];
-
-  // channel(group) selection for chart
-  public selectedChannelGroups: Node[] = [];
-  public selectedXChannel: Node;
-  public selectedYChannels: Node[] = [];
-
-  // measured values of x-channel are cached to avoid unneccessary relaods
-  // on y-channel selection and while creating data points for the chart
-  private xValues = new Map<string, MeasuredValues>();
-  private independentChannels = new Map<string, Node>();
-
-  // chart data
+  // the chart data
   public data: ChartData;
 
-  /** Toolbar ****************/
-
-  // if true, shows pannel with channel(-group) selection
-  public showSelection = true;
-  // if true, x- and y-channels have to be channels with axisType 'X_AXIS', or 'Y_AXIS' respectively.
-  public xyMode = true;
-  // if true, shows chart legend
-  public showLegend = true;
-  // if true, draws datapoints
-  public drawPoints = false;
-  // the charts borderwidth (width of lines, border for points)
-  public lineWidth = 1;
-
-  /**^***********************/
-
+  // options for meausred value data request
   private requestOptions: RequestOptions;
+  // chart properties set via toolbar
+  private toolbarProperties: ChartToolbarProperties;
+  // shows selection pannel if true, set via toolbar
+  public showSelection: boolean;
+  // passed to selection pannel
+  public xyMode: boolean;
 
-  public options = {legend: {display: this.showLegend}};
-
-  /** subscriptions */
-  private chartViewerSub: Subscription;
+  public selectedChannelRows: ChannelSelectionRow[] = [];
 
   constructor(private chartviewerDataService: ChartViewerDataService,
               private chartviewerService: ChartViewerService,
-              private arrayUtil: ArrayUtilService) { }
-
-
-  /****************  Angular lifecycle-hooks ****************************/
+              private arrayUtil: ArrayUtilService,
+              private notificationService: MDMNotificationService) { }
 
   ngOnInit() {
     this.initChartData();
-    this.chartViewerSub = this.chartviewerService.onNodeMetaChange().subscribe(node => this.handleNodeSelectionInNavTree(node));
-  }
-
-  ngOnDestroy() {
-    this.chartViewerSub.unsubscribe();
-  }
-
-  // empty chart on initialization
-  private initChartData() {
-    const dataset = new ChartDataSet('No data', []);
-    dataset.borderColor = '#fff';
-    this.data = new ChartData([], [dataset]);
   }
 
   /**************** Html-template listeners *****************************/
 
-  // --- Data Selection ---
+  /**
+   * Draws chart when data selection changes
+   * @param rows
+   */
+  public onDataSelectionChanged(rows: ChannelSelectionRow[]) {
+    this.selectedChannelRows = rows;
+    this.doChart();
+  }
 
-  // x-axis
-  public onSelectedXChannelChanged(event: Event) {
-    if (this.selectedXChannel != undefined) {
-      const channelGroup = this.findChannelGroup(this.selectedXChannel);
-      this.loadXValues(channelGroup);
-    } else {
-      this.initChartData();
+  /**
+   * Passes xyModeChanges from toolbar to selection pannel
+   * @param isXyMode
+   */
+  public onXyModeChanged(isXyMode: boolean) {
+    this.xyMode = isXyMode;
+  }
+
+  /**
+   * Handles toolbar property changes
+   * @param properties
+   */
+  public onToolbarPropertiesChanged(properties: ChartToolbarProperties) {
+    this.toolbarProperties = properties;
+    this.showSelection = properties.showSelection;
+    this.chart.options = properties.options;
+    if (this.chart.data != undefined) {
+      this.chart.data.datasets.forEach( dataSet => {
+        dataSet.showLine = properties.showLines;
+        dataSet.pointRadius = properties.drawPoints ? 3 : 0;
+        dataSet.borderWidth = properties.lineWidth;
+        dataSet.lineTension = properties.lineTension;
+        dataSet.fill = properties.fillArea;
+      });
+      this.chart.reinit();
     }
   }
 
-  // y-axis
-  public onSelectedYChannelsChanged(event: Event) {
-    if (this.arrayUtil.isNotEmpty(this.selectedYChannels)) {
-      this.doChart();
-    } else {
-      this.initChartData();
-    }
-  }
-
-  // channelgroups
-  public onSelectedChannelGroupsChanged(event: any) {
-      // some channelgroup selected
-    if (this.arrayUtil.isNotEmpty(this.selectedChannelGroups)) {
-      const tmpGroup = event.itemValue;
-      // the currently toggled group is selected (ngModel is updated faster then event.)
-      if (this.isNodeIn(this.selectedChannelGroups, tmpGroup.id)) {
-        this.handleSelectChannelGroup(tmpGroup);
-        // the currently toggled group is deselected
-      } else {
-        this.handleDeselectChannelGroup(tmpGroup);
-      }
-      // no channelgroup selected
-    } else {
-      this.resetChannelData();
-      this.initChartData();
-    }
-  }
-
-  // --- Toolbar ---
-
-  // X- and y-axis options are determined by channels axis type, if xyMode toggled to true
-  public onToggleXyMode(event: Event) {
-    this.reloadAxisSelectOptions();
-  }
-
-  // displays/hides chart legend
-  public onToggleLegend(event: Event) {
-    this.options.legend.display = this.showLegend;
-    this.chart.reinit();
-  }
-
-  // displays/hides visible markers in chart at data points
-  public onToggleDrawPoints(event: Event) {
-    this.chart.data.datasets.forEach(ds => ds.pointRadius = this.drawPoints ? 3 : 0);
-    this.chart.reinit();
-  }
-
-  // displays chart with new line width
-  public onChangeLineWidth(event: Event) {
-    this.chart.data.datasets.forEach(ds => ds.borderWidth = this.lineWidth);
-    this.chart.reinit();
-  }
-
   // Sets new data request options and redraws the graph
   public onRequestOptionsChanged(options: RequestOptions) {
     this.requestOptions = options;
     this.doChart();
   }
 
-  /** Observable response handler *********************************************/
-
-  private handleDeselectChannelGroup(channelGroup: Node) {
-    /**
-     * @TODO implement
-     */
-    this.handleSelectChannelGroup(channelGroup);
-    // this.xChannels = this.xChannels.filter(c => c.relations[0].)
-  }
-
-  /**
-   * Handle channelGroup selection via multiselect in html template
-   * @param channelGroup
-   */
-  private handleSelectChannelGroup(channelGroup: Node) {
-    this.chartviewerDataService.readAxisType(channelGroup)
-      .subscribe(mvls => {
-        this.addXandYchannels(mvls, channelGroup);
-        if (this.xValues.get(channelGroup.id) == undefined) {
-          this.loadXValues(channelGroup);
-        } else {
-          this.doChart();
-        }
-      });
-  }
-
-  private handleNodeSelectionInNavTree(node: Node) {
-    if (node != undefined) {
-      switch (node.type) {
-        case TYPE_MEASUREMENT:
-          this.resetChannelData();
-          this.doChart();
-          break;
-        case TYPE_CHANNELGROUP:
-          this.addChannelGroupToSelection(node.id, node);
-          break;
-        case TYPE_CHANNEL:
-          // add related channel group to selection
-          if (this.arrayUtil.isNotEmpty(this.channelGroups) && this.channels != undefined) {
-            const channelGroup = this.findChannelGroup(node);
-            // this.addChannelGroupToSelection(channelGroupId, this.channelGroups.find(cg => cg.id === channelGroupId));
-            if (!this.isNodeIn(this.selectedChannelGroups, channelGroup.id)) {
-              this.selectedChannelGroups = this.selectedChannelGroups.concat([channelGroup]);
-              this.chartviewerDataService.readAxisType(channelGroup)
-              .subscribe(mvls => {
-                this.addXandYchannels(mvls, channelGroup);
-                this.addChannelToSelection(node, channelGroup);
-              });
-            } else {
-              // if channel is in axis type y, set as selected, if not selected already
-              this.addChannelToSelection(node, channelGroup);
-            }
-          }
-        break;
-      }
-    }
-  }
-
-  /**
-   * Handle channel selection via nav-tree
-   * @param channel
-   * @param channelGroup
-   */
-  private addChannelToSelection(channel: Node, channelGroup: Node) {
-    if (this.isNodeIn(this.yChannels, channel.id)) {
-      const index = this.selectedYChannels.findIndex(c => c.id === channel.id);
-      if (index === -1) {
-        this.selectedYChannels = this.selectedYChannels.concat([channel]);
-        if (this.xValues.get(channelGroup.id) == undefined) {
-          this.loadXValues(channelGroup);
-        } else {
-          this.doChart();
-        }
-      }
-      // if channel is of axis type x, set as x channel, if not set already
-    } else if (this.isNodeIn(this.xChannels, channel.id)) {
-      if (this.selectedXChannel == undefined || this.selectedXChannel.id === channel.id) {
-        this.selectedXChannel = channel;
-        this.loadXValues(channelGroup);
-      }
-    }
-  }
-
-  /**
-   * Handle channelGroup selection via nav-tree
-   * @param id
-   * @param channelGroup
-   */
-  private addChannelGroupToSelection(id: string, channelGroup: Node) {
-    if (this.selectedChannelGroups == undefined) {
-      this.selectedChannelGroups = [];
-    }
-    if (!this.isNodeIn(this.selectedChannelGroups, channelGroup.id)) {
-      this.selectedChannelGroups = this.selectedChannelGroups.concat([channelGroup]);
-      this.handleSelectChannelGroup(channelGroup);
-    }
-  }
-
-  /**
-   * Adds options for x- and y-channels depending on given channelGroup
-   *
-   * @param measuredValues
-   * @param channelGroup
-   */
-  private addXandYchannels(measuredValues: MeasuredValues[], channelGroup: Node) {
-    if (this.xyMode) {
-      measuredValues.forEach(mvl => {
-        if (mvl.axisType === 'X_AXIS' || ( mvl.axisType == undefined && mvl.independent)) {
-          const tmpChannels = this.channels.get(channelGroup.id).filter(c => c.name === mvl.name);
-          this.xChannels = this.xChannels.concat(tmpChannels);
-          // set independent column as default x-axis.
-          if (this.selectedXChannel == undefined && mvl.independent) {
-            this.selectedXChannel = tmpChannels[0];
-          }
-          if (mvl.independent) {
-            this.independentChannels.set(channelGroup.id, tmpChannels[0]);
-          }
-        } else if (mvl.axisType === 'Y_AXIS') {
-          this.yChannels = this.yChannels.concat(this.channels.get(channelGroup.id).filter(c => c.name === mvl.name));
-        }
-      });
-    } else {
-      this.xChannels = this.xChannels.concat(this.channels.get(channelGroup.id));
-      this.yChannels = this.yChannels.concat(this.channels.get(channelGroup.id));
-    }
-  }
-
   /********** private methods / class logic ********************************************************/
 
-  /**
-   * Loads measured values for x-axis depending on the channelgroup.
-   * (Is used for eager loading on channelgroup slection.)
-   *
-   * @param channelGroup
-   */
-  private loadXValues(channelGroup: Node) {
-    console.log(this.channels.get(channelGroup.id))
-    console.log(this.selectedXChannel.id)
-    // if (this.isNodeIn(this.channels.get(channelGroup.id), this.selectedXChannel.id)) {
-      // return this.chartviewerDataService.loadMeasuredValues(channelGroup, [this.selectedXChannel])
-    if (this.independentChannels.get(channelGroup.id) != undefined) {
-      return this.chartviewerDataService.loadMeasuredValues(channelGroup, [this.independentChannels.get(channelGroup.id)])
-        .pipe(
-          tap(measuredValues => this.xValues.set(channelGroup.id, Object.assign(new MeasuredValues(), measuredValues[0])))
-        )
-        .subscribe(() => this.doChart());
-    }
-  }
-
-  /**
-   * Resets selections and select options to empty state.
-   */
-  private resetChannelData() {
-    this.selectedYChannels = [];
-    this.selectedXChannel = undefined;
-    this.xChannels = [];
-    this.yChannels = [];
-  }
-
-  /**
-   * Reloads the select options for the x- and y-axis dropdowns
-   */
-  private reloadAxisSelectOptions() {
-    this.xChannels = [];
-    this.yChannels = [];
-    if (this.arrayUtil.isNotEmpty(this.selectedChannelGroups)) {
-      this.selectedChannelGroups.forEach(cg => this.chartviewerDataService.readAxisType(cg)
-        .subscribe(mvls => this.addXandYchannels(mvls, cg)));
-    }
+  // empty chart on initialization
+  private initChartData() {
+    const dataset = new ChartDataSet('No data', []);
+    dataset.borderColor = '#fff';
+    this.data = new ChartData([], [dataset]);
   }
 
   /**
    * Loads measured values for current selection and draws the new chart.
    */
   private doChart() {
-    if (this.arrayUtil.isNotEmpty(this.selectedChannelGroups)
-          && this.arrayUtil.isNotEmpty(this.selectedYChannels)
-          && this.selectedXChannel != undefined
-          && this.requestOptions != undefined) {
+    if (this.arrayUtil.isNotEmpty(this.selectedChannelRows) && this.requestOptions != undefined) {
+      const xChannels = this.selectedChannelRows.map(row => this.chartviewerDataService.loadMeasuredValues(
+        row.channelGroup, [row.xChannel], this.requestOptions.startIndex, this.requestOptions.requestSize));
+      forkJoin(xChannels)
+        .pipe(
+          map(array => array.map((mea, index) => ({yChannel: this.selectedChannelRows[index].yChannel, measuredValues: mea[0]}))),
+          flatMap(xValues => this.loadYData(xValues))
+        )
+      .subscribe(resp => this.data = resp);
+    } else {
+      this.initChartData();
+    }
+  }
 
-      const tmpYChannels = new Map<string, Node[]>();
-      this.selectedChannelGroups.forEach(cg =>
-        tmpYChannels.set(cg.id, this.selectedYChannels.filter(c => this.isNodeIn(this.channels.get(cg.id), c.id))));
+  /**
+   * Loads measured values for y-channels, merges them with given values for x
+   * @param xValues
+   */
+  private loadYData(xValues: {yChannel: Node; measuredValues: MeasuredValues}[]) {
+    if (xValues != undefined) {
+      const yChannels = this.groupYChannelsByChannelGroup(this.selectedChannelRows);
+      // const channelGroups = this.selectedChannelGroups.filter(cg => this.arrayUtil.isNotEmpty(yChannels[cg.id]));
+      const channelGroups = Array.from(new Set(this.selectedChannelRows.map(row => row.channelGroup)));
 
-      const tmpChannelGroups = this.selectedChannelGroups.filter(cg => this.arrayUtil.isNotEmpty(tmpYChannels.get(cg.id)));
-      const obs = tmpChannelGroups.map(cg =>
-          this.chartviewerDataService.loadMeasuredValues(
-            cg, tmpYChannels.get(cg.id), this.requestOptions.startIndex, this.requestOptions.requestSize)
-        );
+      const obs = channelGroups.map(cg => this.chartviewerDataService.loadMeasuredValues(
+        cg, yChannels[cg.id], this.requestOptions.startIndex, this.requestOptions.requestSize));
       // forkJoin return observables in order of input array. Therefore channelgroup id has to be like tmpChannelGroups[index].id
-      forkJoin(obs).pipe(
-          map(array => array.map((yData, index) =>
-              yData.map(y => {
-                return this.chartviewerService.toXyDataSet(this.getXValues(tmpChannelGroups[index].id) as number[], y)
+      return forkJoin(obs)
+        .pipe(
+          map(array => array.map((yData, channelGroupIndex) =>
+              yData.map((yValues, yChannelIndex) => {
+                const cgId = channelGroups[channelGroupIndex].id;
+                const xData = this.extractXValues(xValues, yChannels[cgId][yChannelIndex].id);
+                const dataSet = this.chartviewerService.toXyDataSet(xData, yValues);
+                return this.setChartProperties(dataSet);
               }))),
-          map(array => array.map(sets =>
-              sets.map(set => this.chartviewerService.setStandardProperties(set, this.drawPoints, this.lineWidth)))),
           map(sets => new ChartData([], sets.reduce((a, b) => a.concat(b), [])))
-        ).subscribe(r => this.data = r);
+        );
+    }
+  }
+
+  private extractXValues(xValues: {yChannel: Node; measuredValues: MeasuredValues}[], channelId: string) {
+    const val = xValues.find(v => v.yChannel.id === channelId);
+    if (val != undefined ) {
+      return val.measuredValues.getDataArray().values as number[];
     }
   }
 
   /******* Helping functions */
 
-  /**
-   * Returns sequence of the xValues for the specified ChannelGroup, with length and start index given by current request options.
-   * @param channelGroupId
-   */
-  private getXValues(channelGroupId: string) {
-    if (this.xValues.get(channelGroupId) != undefined) {
-      return this.xValues
-        .get(channelGroupId)
-        .getDataArray()
-        .values
-        .slice(this.requestOptions.startIndex); //, this.requestOptions.startIndex + this.requestOptions.requestSize
+  private groupYChannelsByChannelGroup(array: ChannelSelectionRow[]) {
+    return array.reduce(
+      (obj, next) => {
+        const value = next.channelGroup.id;
+        obj[value] = obj[value] || [];
+        obj[value] = obj[value].concat(next.yChannel);
+        return obj;
+      }, {});
+  }
+
+  private setChartProperties(dataset: ChartXyDataSet) {
+    if (!this.toolbarProperties.drawPoints) {
+      dataset.pointRadius = 0;
     }
-  }
+    dataset.showLine = this.toolbarProperties.showLines;
+    dataset.fill = this.toolbarProperties.fillArea;
+    dataset.lineTension = this.toolbarProperties.lineTension;
+    dataset.borderWidth = this.toolbarProperties.lineWidth;
+    const color = '#' + Math.random().toString(16).substr(-6);
+    dataset.borderColor = color;
+    dataset.backgroundColor = color;
 
-  /**
-   * Returns true if node with given id is in the given array.
-   *
-   * @param array the array
-   * @param id the id
-   */
-  private isNodeIn(array: Node[], id: string) {
-    return array.findIndex(n => n.id === id) > -1;
-  }
-
-  /**
-   * Looks up parent channelGroup for channel via the channel map.
-   *
-   * @param channel
-   */
-  private findChannelGroup(channel: Node) {
-    const channelGroupId = Array.from(this.channels.keys())
-            .find(key => this.isNodeIn(this.channels.get(key), channel.id));
-    return this.channelGroups.find(cg => cg.id === channelGroupId);
+    return dataset;
   }
 }
diff --git a/org.eclipse.mdm.application/src/main/webapp/src/app/chartviewer/model/chartviewer.model.ts b/org.eclipse.mdm.application/src/main/webapp/src/app/chartviewer/model/chartviewer.model.ts
index 7ae281d..82089da 100644
--- a/org.eclipse.mdm.application/src/main/webapp/src/app/chartviewer/model/chartviewer.model.ts
+++ b/org.eclipse.mdm.application/src/main/webapp/src/app/chartviewer/model/chartviewer.model.ts
@@ -23,6 +23,9 @@
 export { ChartXyDataSet } from './types/chart-xy-data-set.class';

 export { ChartPoint } from './types/chart-point.class';

 export { RequestOptions } from './types/request-options.class';

+export { ChannelSelectionRow } from './types/channel-selection-row';

+export { ChartToolbarProperties } from './types/chart-toolbar-properties.class';

+

 

 export { PrimeChartDataSet } from './primeNgHelper/prime-chart-data-set.interface';

 export { PrimeChartData } from './primeNgHelper/prime-chart-data.interface';

diff --git a/org.eclipse.mdm.application/src/main/webapp/src/app/chartviewer/model/types/channel-selection-row.ts b/org.eclipse.mdm.application/src/main/webapp/src/app/chartviewer/model/types/channel-selection-row.ts
new file mode 100644
index 0000000..23f0072
--- /dev/null
+++ b/org.eclipse.mdm.application/src/main/webapp/src/app/chartviewer/model/types/channel-selection-row.ts
@@ -0,0 +1,26 @@
+/********************************************************************************

+ * Copyright (c) 2015-2018 Contributors to the Eclipse Foundation

+ *

+ * See the NOTICE file(s) distributed with this work for additional

+ * information regarding copyright ownership.

+ *

+ * This program and the accompanying materials are made available under the

+ * terms of the Eclipse Public License v. 2.0 which is available at

+ * http://www.eclipse.org/legal/epl-2.0.

+ *

+ * SPDX-License-Identifier: EPL-2.0

+ *

+ ********************************************************************************/

+import {Node} from '../../../navigator/node';

+

+export class ChannelSelectionRow {

+  channelGroup: Node;

+  xChannel: Node;

+  yChannel: Node;

+

+  constructor(channelGroup: Node, yChannel: Node, xChannel?: Node) {

+    this.channelGroup = channelGroup;

+    this.yChannel = yChannel;

+    this.xChannel = xChannel;

+  }

+}

diff --git a/org.eclipse.mdm.application/src/main/webapp/src/app/chartviewer/model/types/chart-toolbar-properties.class.ts b/org.eclipse.mdm.application/src/main/webapp/src/app/chartviewer/model/types/chart-toolbar-properties.class.ts
new file mode 100644
index 0000000..454d718
--- /dev/null
+++ b/org.eclipse.mdm.application/src/main/webapp/src/app/chartviewer/model/types/chart-toolbar-properties.class.ts
@@ -0,0 +1,31 @@
+/********************************************************************************

+ * Copyright (c) 2015-2018 Contributors to the Eclipse Foundation

+ *

+ * See the NOTICE file(s) distributed with this work for additional

+ * information regarding copyright ownership.

+ *

+ * This program and the accompanying materials are made available under the

+ * terms of the Eclipse Public License v. 2.0 which is available at

+ * http://www.eclipse.org/legal/epl-2.0.

+ *

+ * SPDX-License-Identifier: EPL-2.0

+ *

+ ********************************************************************************/

+

+export class ChartToolbarProperties {

+

+  // if true, shows pannel with channel(-group) selection

+  public showSelection: boolean;

+  // if true, draws datapoints

+  public drawPoints: boolean;

+  // the charts borderwidth (width of lines, border for points)

+  public lineWidth: number;

+  // if true, draws lines connecting datapoints

+  public showLines: boolean;

+  // if true, fills are below graph

+  public fillArea: boolean;

+  // the interpolation degree. 0 = linear, 0.4 = Bezier

+  public lineTension: number;

+

+  public options: {legend: {display: boolean}};

+}

diff --git a/org.eclipse.mdm.application/src/main/webapp/src/app/chartviewer/model/types/chart-xy-data-set.class.ts b/org.eclipse.mdm.application/src/main/webapp/src/app/chartviewer/model/types/chart-xy-data-set.class.ts
index 4a94e47..90e98fb 100644
--- a/org.eclipse.mdm.application/src/main/webapp/src/app/chartviewer/model/types/chart-xy-data-set.class.ts
+++ b/org.eclipse.mdm.application/src/main/webapp/src/app/chartviewer/model/types/chart-xy-data-set.class.ts
@@ -38,7 +38,7 @@
   borderWidth: number;

   fill: boolean;

   borderColor: string;

-  tension: number;

+  lineTension: number;

   showLine: boolean;

 

   // general

diff --git a/org.eclipse.mdm.application/src/main/webapp/src/app/chartviewer/services/chart-viewer.service.ts b/org.eclipse.mdm.application/src/main/webapp/src/app/chartviewer/services/chart-viewer.service.ts
index 0b55858..f99e8ba 100644
--- a/org.eclipse.mdm.application/src/main/webapp/src/app/chartviewer/services/chart-viewer.service.ts
+++ b/org.eclipse.mdm.application/src/main/webapp/src/app/chartviewer/services/chart-viewer.service.ts
@@ -12,7 +12,7 @@
 
   private nodeMetaSubject = new Subject<Node>();
 
-  constructor() { }
+  constructor() {}
 
   public sendNodeMeta(nodeMeta: Node) {
     this.nodeMetaSubject.next(nodeMeta);
@@ -29,22 +29,6 @@
     return dataset;
   }
 
-  public setStandardProperties(dataset: ChartXyDataSet, drawPoints?: boolean, lineWidth?: number) {
-    if (!drawPoints) {
-      dataset.pointRadius = 0;
-    }
-    // lines
-    dataset.showLine = true;
-    dataset.fill = false;
-    dataset.tension = 0; // linear interpolation
-    dataset.borderWidth = lineWidth;
-    const color = '#' + Math.random().toString(16).substr(-6);
-    dataset.borderColor = color;
-    dataset.backgroundColor = color;
-
-    return dataset;
-  }
-
   private getDataPoints(xData: number[], yData: number[], startIndex = 0) {
     if (xData != undefined && xData.length <= yData.length) {
       return xData.map((x, i) => new ChartPoint(x, yData[i]));
diff --git a/org.eclipse.mdm.application/src/main/webapp/src/assets/i18n/de.json b/org.eclipse.mdm.application/src/main/webapp/src/assets/i18n/de.json
index 906aeec..e39f921 100644
--- a/org.eclipse.mdm.application/src/main/webapp/src/assets/i18n/de.json
+++ b/org.eclipse.mdm.application/src/main/webapp/src/assets/i18n/de.json
@@ -317,5 +317,31 @@
 			"tooltip-save-view": "Ansicht speichern",
 			"tooltip-select-view": "Ansicht auswählen"
 		}
+	},
+	"chartviewer": {
+		"request-options": {},
+		"xy-chart-data-selection-panel": {
+			"select-channel-placeholder": "Kanal wählen"
+		},
+		"xy-chart-viewer": {},
+		"xy-chart-viewer-nav-card": {
+			"no-node-selected": "Kein Knoten ausgewählt"
+		},
+		"xy-chart-viewer-toolbar": {
+			"hide-data-selection-panel": "Datenauswahlpanel verbergen",
+			"show-data-selection-panel": "Datenauswahlpanel anzeigen",
+			"activate-xy-mode": "Kanal Auswahloptionen nach Achsentyp filtern",
+			"deactivate-xy-mode": "Alle Kanäle als Auswahloptionen anzeigen",
+			"hide-chart-legend": "Legende des Diagramms verbergen",
+			"show-chart-legend": "Legende des Diagramms anzeigen",
+			"line-width": "Linienstärke",
+			"show-lines": "Verbindungslinien anzeigen",
+			"hide-lines": "Verbindungslinien verbergen",
+			"fill-area": "Fläche unter dem Graph füllen",
+			"clear-area": "Fläche unter dem Graph leeren",
+			"show-datapoints": "Datenpunkte markieren",
+			"hide-datapoints": "Datenpunkte verbergen",
+			"tension": "Tension: 0 = Linear, 0.4 = Bezierkurve"
+		}
 	}
 }
\ No newline at end of file
diff --git a/org.eclipse.mdm.application/src/main/webapp/src/assets/i18n/en.json b/org.eclipse.mdm.application/src/main/webapp/src/assets/i18n/en.json
index 2ef7534..fe1267e 100644
--- a/org.eclipse.mdm.application/src/main/webapp/src/assets/i18n/en.json
+++ b/org.eclipse.mdm.application/src/main/webapp/src/assets/i18n/en.json
@@ -317,5 +317,31 @@
 			"tooltip-save-view": "Save view",
 			"tooltip-select-view": "Select view"
 		}
+	},
+	"chartviewer": {
+		"request-options": {},
+		"xy-chart-data-selection-panel": {
+			"select-channel-placeholder": "Select Channel"
+		},
+		"xy-chart-viewer": {},
+		"xy-chart-viewer-nav-card": {
+			"no-node-selected": "No node selected"
+		},
+		"xy-chart-viewer-toolbar": {
+			"hide-data-selection-panel": "Hide data selection panel",
+			"show-data-selection-panel": "Show data selection panel",
+			"activate-xy-mode": "Filter channel options by axis-type",
+			"deactivate-xy-mode": "Provide all channel options",
+			"hide-chart-legend": "Hide chart legend",
+			"show-chart-legend": "Show chart legend",
+			"line-width": "Line width",
+			"show-lines": "Draw lines",
+			"hide-lines": "Hide lines",
+			"fill-area": "Fill area underneath the graph",
+			"clear-area": "Clear area underneath the graph",
+			"show-datapoints": "Mark datapoints",
+			"hide-datapoints": "Hide datapoints",
+			"tension": "Line tension: 0 = linear, 0.4 = Bezier curve"
+		}
 	}
 }
\ No newline at end of file
diff --git a/org.eclipse.mdm.application/src/main/webapp/src/styles.css b/org.eclipse.mdm.application/src/main/webapp/src/styles.css
index 4334b66..9905f4d 100644
--- a/org.eclipse.mdm.application/src/main/webapp/src/styles.css
+++ b/org.eclipse.mdm.application/src/main/webapp/src/styles.css
@@ -25,7 +25,7 @@
 
 .navbar {
   font-size: 1em;
-  margin-bottom: 1em;
+  margin-bottom: 0.5em;
   padding: 0rem 1rem;
 }