diff --git a/src/app/components/shared/_dialogs/cloud-configuration/cloud-configuration.component.html b/src/app/components/shared/_dialogs/cloud-configuration/cloud-configuration.component.html
index e624c53ff3199d6849b5a70c467a9787a48459dd..6a920d6894ebbfa54966e72a5903e14ddbcfbacf 100644
--- a/src/app/components/shared/_dialogs/cloud-configuration/cloud-configuration.component.html
+++ b/src/app/components/shared/_dialogs/cloud-configuration/cloud-configuration.component.html
@@ -1,13 +1,17 @@
 <div id="wholeDialog" class="drawer-container" fxLayout="column" fxLayoutGap="5px">
-  <div class="cloud-configuration-form" fxLayout="column" *ngIf="!extendedView">
+  <div class="cloud-configuration-form" fxLayout="column" *ngIf="!extendedView && !cleanUpView">
     <h2>{{'tag-cloud-config.title' | translate}}</h2>
-    <div class="input-row special-settings" fxLayout="row" fxLayoutGap="5px" fxLayout.xs="column">
+    <div class="input-row special-settings demo-cloud-settings" fxLayout="row" fxLayoutGap="5px" fxLayout.xs="column">
       <div class="input-row" fxLayout="row" fxLayoutGap="5px" fxLayout.xs="column">
-        <mat-slide-toggle fxFlex (change)="parent.demoToggle()" [checked]="parent.isDemo"
-          [ngModelOptions]="{standalone: true}">Demo Cloud</mat-slide-toggle>
+        <mat-slide-toggle fxFlex (change)="parent.dataManager.demoActive = !parent.dataManager.demoActive"
+                          [checked]="parent.dataManager.demoActive"
+                          [ngModelOptions]="{standalone: true}">Demo Cloud</mat-slide-toggle>
       </div>
-      <div  class="button-row weight-class-button">
-        <button (click)="toggleExtendedView()" mat-button class="primary">{{'tag-cloud-config.extended-btn' | translate}}</button>
+    </div>
+    <div class="input-row specialButtons special-settings" fxLayout="row" fxLayoutGap="5px" fxLayout.xs="column">
+      <div class="button-row weight-class-buttons">
+        <button (click)="toggleExtendedView()" mat-button class="primary" id="extendedViewButton">{{'tag-cloud-config.extended-btn' | translate}}</button>
+        <button (click)="toggleCleanupView()" mat-button class="primary">Tag-Cleanup</button>
       </div>
     </div>
     <h3>{{'tag-cloud-config.general' | translate}}</h3>
@@ -98,6 +102,7 @@
     </div>
     <h2>{{'tag-cloud-config.weight-class-settings' | translate}}</h2>
     <div *ngFor="let weightClass of weightClasses" class="weight-class-setting">
+      <div class ="weight-class-setting-content">
       <h3 class="weight-class-heading">{{'tag-cloud-config.weight-class' | translate}} {{weightClasses.indexOf(weightClass) + 1}}</h3>
       <div class="input-row" fxLayout="column" fxLayoutGap="5px">
         <div class="input-row" fxLayout="column" fxLayoutGap="5px">
@@ -113,12 +118,51 @@
           </div>
         </div>
       </div>
-      <div class="input-row" fxLayout="column" fxLayoutGap="5px">
-        <mat-label class="label-text">{{'tag-cloud-config.weight-number' | translate}}</mat-label>
-        <mat-slider [value]="weightClass.maxTagNumber" min="0" max="30" step="1"
+      
+      <div class="input-row" fxLayout="column" fxLayoutGap="5px" *ngIf="weightClass.actualTagNumber > 0 && !parent.dataManager.demoActive">
+        <mat-label class="label-text" >{{'tag-cloud-config.weight-number' | translate}}</mat-label>
+        <mat-slider [value]="weightClass.maxTagNumber" min="0" [max]="weightClass.actualTagNumber" step="1"
                     [(ngModel)]="weightClass.maxTagNumber" [ngModelOptions]="{standalone: true}" (change)="valueChanged()"
                     [thumbLabel]="true" matTooltip="{{'tag-cloud-config.weight-number-tooltip' | translate}}"></mat-slider>
       </div>
+      <div class="input-row" fxLayout="column" fxLayoutGap="5px">
+        <mat-label class="label-text">{{'tag-cloud-config.rotate-weight' | translate}}</mat-label>
+        <mat-slider [value]="weightClass.rotationAngle" min="-180" max="180" step="1"
+                    [(ngModel)]="weightClass.rotationAngle" [ngModelOptions]="{standalone: true}" (change)="valueChanged()"
+                    [thumbLabel]="true" matTooltip="{{'tag-cloud-config.weight-number-tooltip' | translate}}"></mat-slider>
+      </div>
+    </div>
+  </div>
+  </div>
+  <div class="cloud-configuration-form" fxLayout="column" *ngIf="cleanUpView">
+    <div  class="weight-class-button button-row">
+      <button (click)="toggleCleanupView()" mat-button class="primary">{{'tag-cloud-config.back-btn' | translate}}</button>
     </div>
+    <h2>{{'tag-cloud-config.cleanUpView' | translate}}</h2>
+    <div class="input-row special-settings automatic-spelling" fxLayout="row" fxLayoutGap="5px" fxLayout.xs="column">
+      <div class="input-row" fxLayout="row" fxLayoutGap="5px" fxLayout.xs="column">
+        <mat-slide-toggle matTooltip="{{'tag-cloud-config.automatic-spelling-tooltip' | translate}}" [(ngModel)]="cloudParameters.checkSpelling" [checked]="cloudParameters.checkSpelling" [ngModelOptions]="{standalone: true}" (change)="valueChanged()">{{'tag-cloud-config.automatic-spelling' | translate}}</mat-slide-toggle>
+      </div>
+    </div>
+      <div class="input-row special-settings automatic-spelling" fxLayout="row" fxLayoutGap="5px" fxLayout.xs="column">
+        <mat-radio-group matTooltip="{{'tag-cloud-config.notation-tooltip' | translate}}" aria-label="Notation:"> {{'tag-cloud-config.notation' | translate}}
+          <div><mat-radio-button value="1" (change)="textStyleChanged(1)" [checked]="cloudParameters.textTransform == 1">{{'tag-cloud-config.lowerCase' | translate}}</mat-radio-button> </div>
+          <div><mat-radio-button value="2" (change)="textStyleChanged(2)" [checked]="cloudParameters.textTransform == 2">{{'tag-cloud-config.capitalization' | translate}}</mat-radio-button> </div>
+          <div><mat-radio-button value="0" (change)="textStyleChanged(0)" [checked]="cloudParameters.textTransform == 0">{{'tag-cloud-config.standard' | translate}}</mat-radio-button> </div>
+        </mat-radio-group>
+      </div>
+      <div class="input-row special-settings alphabetical-sorting" fxLayout="row" fxLayoutGap="5px" fxLayout.xs="column">
+        <div class="input-row" fxLayout="row" fxLayoutGap="5px" fxLayout.xs="column">
+          <mat-slide-toggle matTooltip="{{'tag-cloud-config.alphabetical-sorting-tooltip' | translate}}" [(ngModel)]="cloudParameters.sortAlphabetically" [checked]="cloudParameters.sortAlphabetically" [ngModelOptions]="{standalone: true}"(change)="valueChanged()">{{'tag-cloud-config.alphabetical-sorting' | translate}}</mat-slide-toggle>
+        </div>
+      </div>
+      <div class="input-row" fxLayout="column" fxLayoutGap="5px">
+        <mat-form-field fxFlex fxLayout.xs="column">
+          <mat-label>{{'tag-cloud-config.highestWeight' | translate}}</mat-label>
+          <input #highestWeight matTooltip="{{'tag-cloud-config.highestWeight-tooltip' | translate}}" [value]="cloudParameters.highestWeight" matInput type="number"
+            [(ngModel)]="cloudParameters.highestWeight" [ngModelOptions]="{standalone: true}" (change)="valueChanged()"
+            min="0" max="150" step="1"/>
+        </mat-form-field>
+      </div>
   </div>
 </div>
diff --git a/src/app/components/shared/_dialogs/cloud-configuration/cloud-configuration.component.scss b/src/app/components/shared/_dialogs/cloud-configuration/cloud-configuration.component.scss
index 53be4b33ba8bb45d14fef1af8016e198354791c5..faaf8bd4ab99c5b9349ad95b3e931b10116e778f 100644
--- a/src/app/components/shared/_dialogs/cloud-configuration/cloud-configuration.component.scss
+++ b/src/app/components/shared/_dialogs/cloud-configuration/cloud-configuration.component.scss
@@ -75,6 +75,7 @@ mat-divider {
   display: block;
   position: relative;
   right: 40px;
+  pointer-events: none;
 }
 
 ::ng-deep .mat-slide-toggle-thumb{
@@ -152,6 +153,7 @@ mat-divider {
 ::ng-deep.custom-color-picker{
   opacity: 0;
   z-index: -1;
+  cursor: pointer;
 }
 .custom-color-picker-text{
   position: absolute;
@@ -167,7 +169,7 @@ mat-divider {
   opacity: 0.2;
 }
 
-.weight-class-setting {
+.weight-class-setting-content {
   border-top: 3px solid var(--primary);
 }
 
@@ -176,12 +178,24 @@ mat-divider {
   color: var(--on-dialog);
 }
 
-.weight-class-button {
+#extendedViewButton {
+  margin-right: 10px;
+}
+
+.demo-cloud-settings {
+  border-bottom: none;
+}
+
+.weight-class-buttons {
   margin-bottom: 0;
 }
 
 .special-settings{
-  border-top: 2px solid var(--primary);
+  border-top: none;
   border-bottom: 2px solid var(--primary);
   padding: 10px 0;
+}
+
+#rotation{
+  margin-top: 10px;
 }
\ No newline at end of file
diff --git a/src/app/components/shared/_dialogs/cloud-configuration/cloud-configuration.component.ts b/src/app/components/shared/_dialogs/cloud-configuration/cloud-configuration.component.ts
index c4d51096b37ee8de9e1923ccb5f6cf039af0d1b3..94f2117a5e6498a1234e130d54c39cc4b0d2b192 100644
--- a/src/app/components/shared/_dialogs/cloud-configuration/cloud-configuration.component.ts
+++ b/src/app/components/shared/_dialogs/cloud-configuration/cloud-configuration.component.ts
@@ -1,7 +1,8 @@
-import { Component, Input, OnInit, SimpleChanges } from '@angular/core';
+import { Component, Input, OnInit } from '@angular/core';
 import { TranslateService } from '@ngx-translate/core';
 import { TagCloudComponent } from '../../tag-cloud/tag-cloud.component';
-import { CloudParameters } from '../../tag-cloud/tag-cloud.interface';
+import { TagCloudMetaDataCount } from '../../tag-cloud/tag-cloud.data-manager';
+import { CloudParameters, CloudTextStyle } from '../../tag-cloud/tag-cloud.interface';
 import { WeightClass } from './weight-class.interface';
 
 @Component({
@@ -9,103 +10,170 @@ import { WeightClass } from './weight-class.interface';
   templateUrl: './cloud-configuration.component.html',
   styleUrls: ['./cloud-configuration.component.scss'],
 })
-export class CloudConfigurationComponent implements OnInit{
+export class CloudConfigurationComponent implements OnInit {
   @Input() parent: TagCloudComponent;
+  CloudTextStyle: CloudTextStyle;
   cloudParameters: CloudParameters;
   defaultCloudParameters: CloudParameters;
   oldCloudParameters: CloudParameters;
+  countPerWeight: TagCloudMetaDataCount;
   extendedView: boolean;
-  weightClasses: WeightClass[]=[
-    {maxTagNumber: 20,
-    tagColor: '#8800ff'},
-    {maxTagNumber: 20,
-    tagColor: '#ff00ff'},
-    {maxTagNumber: 17,
-    tagColor: '#ffea00'},
-    {maxTagNumber: 15,
-    tagColor: '#00CC99'},
-    {maxTagNumber: 12,
-    tagColor: '#00CC66'},
-    {maxTagNumber: 10,
-    tagColor: '#0033FF'},
-    {maxTagNumber: 8,
-    tagColor: '#CC0099'},
-    {maxTagNumber: 7,
-    tagColor: '#FF3399'},
-    {maxTagNumber: 6,
-    tagColor: '#FFFF00'},
-    {maxTagNumber: 5,
-    tagColor: '#FF0000'},
+  cleanUpView: boolean;
+  automaticSpelling: boolean;
+  lowerCase: boolean;
+  capitalization: boolean;
+  standard: boolean;
+  alphabeticalSorting: boolean;
+  rotation: number;
+  highestWeight: number;
+  weightClasses: WeightClass[] = [
+    {
+      maxTagNumber: 20,
+      tagColor: '#8800ff',
+      actualTagNumber: 5,
+      rotationAngle: 0
+    },
+    {
+      maxTagNumber: 20,
+      tagColor: '#ff00ff',
+      actualTagNumber: 5,
+      rotationAngle: 0,
+    },
+    {
+      maxTagNumber: 17,
+      tagColor: '#ffea00',
+      actualTagNumber: 5,
+      rotationAngle: 0
+    },
+    {
+      maxTagNumber: 15,
+      tagColor: '#00CC99',
+      actualTagNumber: 5,
+      rotationAngle: 0
+    },
+    {
+      maxTagNumber: 12,
+      tagColor: '#00CC66',
+      actualTagNumber: 5,
+      rotationAngle: 0
+    },
+    {
+      maxTagNumber: 10,
+      tagColor: '#0033FF',
+      actualTagNumber: 5,
+      rotationAngle: 0
+    },
+    {
+      maxTagNumber: 8,
+      tagColor: '#CC0099',
+      actualTagNumber: 5,
+      rotationAngle: 0
+    },
+    {
+      maxTagNumber: 7,
+      tagColor: '#FF3399',
+      actualTagNumber: 5,
+      rotationAngle: 0
+    },
+    {
+      maxTagNumber: 6,
+      tagColor: '#FFFF00',
+      actualTagNumber: 5,
+      rotationAngle: 0
+    },
+    {
+      maxTagNumber: 5,
+      tagColor: '#FF0000',
+      actualTagNumber: 5,
+      rotationAngle: 0
+    },
   ];
 
 
   isTestCloud = false;
 
-  constructor(private translateService: TranslateService) {}
+  constructor(private translateService: TranslateService) { }
 
   ngOnInit() {
     this.translateService.use(localStorage.getItem('currentLang'));
-    this.cloudParameters = this.parent.getCurrentCloudParameters();
-    this.defaultCloudParameters = this.parent.getCurrentCloudParameters();    
-    this.parseArrayToJsonWeightClasses();
+    this.cloudParameters = this.parent.currentCloudParameters;
+    this.defaultCloudParameters = this.parent.currentCloudParameters;
+    this.parent.dataManager.getMetaData().subscribe((value)=>{
+      this.countPerWeight = value.countPerWeight;
+      this.parseArrayToJsonWeightClasses();
+    });
     this.extendedView = false;
+    this.cleanUpView = false;
+    this.automaticSpelling = true;
+    this.lowerCase = true;
+    this.capitalization = false;
+    this.standard = false;
+    this.alphabeticalSorting = true;
+    this.rotation = 360;
+    this.highestWeight = 100;
   }
 
-  fontColorChanged(value: string){
+  fontColorChanged(value: string) {
     this.cloudParameters.fontColor = value;
     this.valueChanged();
   }
 
-  backgroundColorChanged(value: string){
+  backgroundColorChanged(value: string) {
     this.cloudParameters.backgroundColor = value;
     this.valueChanged();
   }
 
-  parseArrayToJsonWeightClasses(){
-    this.cloudParameters.cloudWeightCount.forEach((element, i) => {
-      this.weightClasses[i].maxTagNumber = element;
-    });
-
-    this.cloudParameters.cloudWeightColor.forEach((element, i) => {
-      this.weightClasses[i].tagColor = element;
+  parseArrayToJsonWeightClasses() {
+    this.cloudParameters.cloudWeightSettings.forEach((element, i) => {
+       this.weightClasses[i].tagColor = element.color;
+       this.weightClasses[i].actualTagNumber = this.countPerWeight[i];
+       this.weightClasses[i].rotationAngle = element.rotation;
     });
   }
-  
-  parseJsonToArrayWeightClasses(){
+
+  parseJsonToArrayWeightClasses() {
     this.weightClasses.forEach((element, i) => {
-      this.cloudParameters.cloudWeightCount[i] =  element.maxTagNumber;
-      this.cloudParameters.cloudWeightColor[i] =  element.tagColor;
+      this.cloudParameters.cloudWeightSettings[i].maxVisibleElements = element.maxTagNumber;
+      this.cloudParameters.cloudWeightSettings[i].color = element.tagColor;
+      this.cloudParameters.cloudWeightSettings[i].rotation = element.rotationAngle;
     });
   }
 
-
-  valueChanged(){
+  valueChanged() {
     this.parseJsonToArrayWeightClasses();
-    this.parent.setCloudParameters(this.cloudParameters, false);    
+    this.parent.setCloudParameters(this.cloudParameters, false);
   }
 
-  cancel(){
-    this.parent.isDemo = true;
-    this.parent.demoToggle();
+  cancel() {
+    this.parent.tagCloudDataManager.demoActive = false;
     this.parent.setCloudParameters(this.defaultCloudParameters);
     this.parent.configurationOpen = false;
   }
 
-  save(){
-    this.parent.isDemo = true;
-    this.parent.demoToggle();
+  save() {
+    this.parent.tagCloudDataManager.demoActive = false;
     this.parent.setCloudParameters(this.cloudParameters);
     this.parent.configurationOpen = false;
   }
 
-  toggleExtendedView(){
+  toggleExtendedView() {
+    this.cleanUpView = false;
     this.extendedView = !this.extendedView;
   }
 
+  toggleCleanupView() {
+    this.cleanUpView = !this.cleanUpView;
+    this.extendedView = false;
+  }
 
   weightColorChanged(index: number, event: string): void {
     this.weightClasses[index].tagColor = event;
     this.valueChanged();
   }
 
+  textStyleChanged(val: CloudTextStyle) {
+    this.cloudParameters.textTransform = val;
+    this.valueChanged();
+  }
+
 }
diff --git a/src/app/components/shared/_dialogs/cloud-configuration/weight-class.interface.ts b/src/app/components/shared/_dialogs/cloud-configuration/weight-class.interface.ts
index 771122ea4845ccb0e64b798ce5106a71dee01354..237959840512a99f0a5880fc6f98bfb51d58dcdc 100644
--- a/src/app/components/shared/_dialogs/cloud-configuration/weight-class.interface.ts
+++ b/src/app/components/shared/_dialogs/cloud-configuration/weight-class.interface.ts
@@ -1,4 +1,6 @@
 export interface WeightClass {
     maxTagNumber: number;
     tagColor: string;
-}
\ No newline at end of file
+    actualTagNumber: number;
+    rotationAngle: number;
+}
diff --git a/src/app/components/shared/header/header.component.ts b/src/app/components/shared/header/header.component.ts
index be8879e5208fc08588ae5330ec9f7afbf159f09c..c756da05480e64471a63ac955802e8fb18edf25e 100644
--- a/src/app/components/shared/header/header.component.ts
+++ b/src/app/components/shared/header/header.component.ts
@@ -23,7 +23,7 @@ import { MotdService } from '../../../services/http/motd.service';
 import { TopicCloudFilterComponent } from '../_dialogs/topic-cloud-filter/topic-cloud-filter.component';
 import { RoomService } from '../../../services/http/room.service';
 import { Room } from '../../../models/room';
-import { TagCloudHeaderDataOverview } from '../tag-cloud/tag-cloud.interface';
+import { TagCloudMetaData } from '../tag-cloud/tag-cloud.data-manager';
 
 @Component({
   selector: 'app-header',
@@ -43,7 +43,6 @@ export class HeaderComponent implements OnInit {
   commentsCountUsers = 0;
   commentsCountKeywords = 0;
 
-
   constructor(public location: Location,
               private authenticationService: AuthenticationService,
               private notificationService: NotificationService,
@@ -66,7 +65,7 @@ export class HeaderComponent implements OnInit {
         this.motdService.requestDialog();
       });
     });
-    this.eventService.on<TagCloudHeaderDataOverview>('tagCloudHeaderDataOverview').subscribe(data => {
+    this.eventService.on<TagCloudMetaData>('tagCloudHeaderDataOverview').subscribe(data => {
       this.commentsCountQuestions = data.commentCount;
       this.commentsCountUsers = data.userCount;
       this.commentsCountKeywords = data.tagCount;
diff --git a/src/app/components/shared/tag-cloud/tag-cloud.component.html b/src/app/components/shared/tag-cloud/tag-cloud.component.html
index 22a6bfdf975f1229946181553751bd0655e7abc3..16503d3c23d80a55096b785b95eb4c42cbaa7e14 100644
--- a/src/app/components/shared/tag-cloud/tag-cloud.component.html
+++ b/src/app/components/shared/tag-cloud/tag-cloud.component.html
@@ -16,7 +16,7 @@
           [width]="options.width"
           [height]="options.height"
           [overflow]="options.overflow"
-          [delay]="options.delay"
+          [delay]="currentCloudParameters.delayWord"
           [randomizeAngle]="false"
           [zoomOnHover]="zoomOnHoverOptions"
           [realignOnResize]="false">
diff --git a/src/app/components/shared/tag-cloud/tag-cloud.component.ts b/src/app/components/shared/tag-cloud/tag-cloud.component.ts
index 410d9dc1ea6bba27a0a2891a736741fbf425d99a..f4a61776121d31497188f1b0dfcbdd6df9b8f2e4 100644
--- a/src/app/components/shared/tag-cloud/tag-cloud.component.ts
+++ b/src/app/components/shared/tag-cloud/tag-cloud.component.ts
@@ -1,14 +1,14 @@
-import { Component, OnInit, ViewChild, Input, AfterViewInit, OnDestroy } from '@angular/core';
+import { AfterViewInit, Component, Input, OnDestroy, OnInit, ViewChild } from '@angular/core';
 
 import {
   CloudData,
   CloudOptions,
   Position,
-  ZoomOnHoverOptions,
-  TagCloudComponent as TCloudComponent
+  TagCloudComponent as TCloudComponent,
+  ZoomOnHoverOptions
 } from 'angular-tag-cloud-module';
 import { CommentService } from '../../../services/http/comment.service';
-import { Result, SpacyService } from '../../../services/http/spacy.service';
+import { SpacyService } from '../../../services/http/spacy.service';
 import { Comment } from '../../../models/comment';
 import { LanguageService } from '../../../services/util/language.service';
 import { TranslateService } from '@ngx-translate/core';
@@ -23,17 +23,17 @@ import { ActivatedRoute } from '@angular/router';
 import { UserRole } from '../../../models/user-roles.enum';
 import { RoomService } from '../../../services/http/room.service';
 import { ThemeService } from '../../../../theme/theme.service';
-import { CloudParameters, CloudWeightColor, CloudWeightCount, TagCloudHeaderDataOverview } from './tag-cloud.interface';
+import { cloneParameters, CloudParameters, CloudTextStyle, CloudWeightSettings } from './tag-cloud.interface';
 import { TopicCloudAdministrationComponent } from '../_dialogs/topic-cloud-administration/topic-cloud-administration.component';
 import { WsCommentServiceService } from '../../../services/websockets/ws-comment-service.service';
-import { demoMap } from './demoData';
+import { TagCloudDataManager } from './tag-cloud.data-manager';
 
 class CustomPosition implements Position {
   left: number;
   top: number;
 
   constructor(public relativeLeft: number,
-    public relativeTop: number) {
+              public relativeTop: number) {
   }
 
   updatePosition(width: number, height: number, text: string, style: CSSStyleDeclaration) {
@@ -46,32 +46,16 @@ class CustomPosition implements Position {
 
 class TagComment implements CloudData {
   constructor(public color: string,
-    public external: boolean,
-    public link: string,
-    public position: Position,
-    public rotate: number,
-    public text: string,
-    public tooltip: string,
-    public weight: number) {
+              public external: boolean,
+              public link: string,
+              public position: Position,
+              public rotate: number,
+              public text: string,
+              public tooltip: string,
+              public weight: number) {
   }
 }
 
-//CSS styles Array
-type TagCloudStyleData = [
-  string, // hover
-  string, // w1
-  string, // w2
-  string, // w3
-  string, // w4
-  string, // w5
-  string, // w6
-  string, // w7
-  string, // w8
-  string, // w9
-  string, // w10
-  string // background
-];
-
 const colorRegex = /rgba?\((\d+), (\d+), (\d+)(?:, (\d(?:\.\d+)?))?\)/;
 const transformationScaleKiller = /scale\([^)]*\)/;
 const defaultColors: string[] = [
@@ -108,29 +92,20 @@ const getResolvedDefaultColors = (): string[] => {
   return results;
 };
 
-const setGlobalStyles = (styles: TagCloudStyleData): void => {
-  let customTagCloudStyles = document.getElementById('tagCloudStyles') as HTMLStyleElement;
-  if (!customTagCloudStyles) {
-    customTagCloudStyles = document.createElement('style');
-    customTagCloudStyles.id = 'tagCloudStyles';
-    document.head.appendChild(customTagCloudStyles);
-  }
-  const rules = customTagCloudStyles.sheet.cssRules;
-  for (let i = rules.length - 1; i >= 0; i--) {
-    customTagCloudStyles.sheet.deleteRule(i);
-  }
-  for (let i = 1; i <= 10; i++) {
-    customTagCloudStyles.sheet.insertRule('.spacyTagCloud > span.w' + i + ' { ' + styles[i] + ' }', rules.length);
-    customTagCloudStyles.sheet.insertRule('.spacyTagCloud > span.w' + i + ' > a { ' + styles[i] + ' }', rules.length);
-  }
-  customTagCloudStyles.sheet.insertRule('.spacyTagCloud > span:hover { ' + styles[0] + ' }', rules.length);
-  customTagCloudStyles.sheet.insertRule('.spacyTagCloud > span:hover > a { ' + styles[0] + ' }', rules.length);
-  customTagCloudStyles.sheet.insertRule('.spacyTagCloudContainer {' + styles[11] + '}', rules.length);
-};
-
 const getDefaultCloudParameters = (): CloudParameters => {
   const resDefaultColors = getResolvedDefaultColors();
-  const resWeightColors = resDefaultColors.slice(1, 11) as CloudWeightColor;
+  const weightSettings: CloudWeightSettings = [
+    {maxVisibleElements: -1, color: resDefaultColors[1], rotation: 0},
+    {maxVisibleElements: -1, color: resDefaultColors[2], rotation: 0},
+    {maxVisibleElements: -1, color: resDefaultColors[3], rotation: 0},
+    {maxVisibleElements: -1, color: resDefaultColors[4], rotation: 0},
+    {maxVisibleElements: -1, color: resDefaultColors[5], rotation: 0},
+    {maxVisibleElements: -1, color: resDefaultColors[6], rotation: 0},
+    {maxVisibleElements: -1, color: resDefaultColors[7], rotation: 0},
+    {maxVisibleElements: -1, color: resDefaultColors[8], rotation: 0},
+    {maxVisibleElements: -1, color: resDefaultColors[9], rotation: 0},
+    {maxVisibleElements: -1, color: resDefaultColors[10], rotation: 0},
+  ];
   return {
     backgroundColor: resDefaultColors[11],
     fontColor: resDefaultColors[0],
@@ -141,8 +116,10 @@ const getDefaultCloudParameters = (): CloudParameters => {
     hoverDelay: 0.4,
     delayWord: 0,
     randomAngles: false,
-    cloudWeightColor: resWeightColors,
-    cloudWeightCount: [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1]
+    checkSpelling: true,
+    sortAlphabetically: true,
+    textTransform: CloudTextStyle.lowercase,
+    cloudWeightSettings: weightSettings
   };
 };
 
@@ -153,11 +130,10 @@ const getDefaultCloudParameters = (): CloudParameters => {
 })
 export class TagCloudComponent implements OnInit, AfterViewInit, OnDestroy {
 
-  @ViewChild(TCloudComponent, { static: false }) child: TCloudComponent;
+  @ViewChild(TCloudComponent, {static: false}) child: TCloudComponent;
   @Input() user: User;
   @Input() roomId: string;
   room: Room;
-  headerInterface = null;
   directSend = true;
   shortId: string;
   options: CloudOptions = {
@@ -176,49 +152,70 @@ export class TagCloudComponent implements OnInit, AfterViewInit, OnDestroy {
   };
   userRole: UserRole;
   data: TagComment[] = [];
-  sorted = false;
   debounceTimer = 0;
   lastDebounceTime = 0;
   configurationOpen = false;
-  randomizeAngle = false;
   isLoading = true;
-  dataSize: CloudWeightCount;
-
-  //Demo Toggle
-  isDemo: boolean = false;
-  oldCloudData = [];
+  //Subscriptions
+  headerInterface = null;
+  themeSubscription = null;
+  readonly dataManager: TagCloudDataManager;
+  private _currentSettings: CloudParameters;
 
   constructor(private commentService: CommentService,
-    private spacyService: SpacyService,
-    private langService: LanguageService,
-    private translateService: TranslateService,
-    public dialog: MatDialog,
-    private notificationService: NotificationService,
-    public eventService: EventService,
-    private authenticationService: AuthenticationService,
-    private route: ActivatedRoute,
-    protected roomService: RoomService,
-    private themeService: ThemeService,
-    private wsCommentService: WsCommentServiceService) {
+              private spacyService: SpacyService,
+              private langService: LanguageService,
+              private translateService: TranslateService,
+              public dialog: MatDialog,
+              private notificationService: NotificationService,
+              public eventService: EventService,
+              private authenticationService: AuthenticationService,
+              private route: ActivatedRoute,
+              protected roomService: RoomService,
+              private themeService: ThemeService,
+              private wsCommentService: WsCommentServiceService) {
     this.roomId = localStorage.getItem('roomId');
     this.langService.langEmitter.subscribe(lang => {
       this.translateService.use(lang);
     });
+    this.dataManager = new TagCloudDataManager(wsCommentService, commentService);
+    this._currentSettings = TagCloudComponent.getCurrentCloudParameters();
+  }
+
+  private static getCurrentCloudParameters(): CloudParameters {
+    const jsonData = localStorage.getItem('tagCloudConfiguration');
+    const temp: CloudParameters = jsonData != null ? JSON.parse(jsonData) : null;
+    const elem = getDefaultCloudParameters();
+    if (temp != null) {
+      for (const key in Object.keys(elem)) {
+        if (temp[key] !== undefined) {
+          elem[key] = temp[key];
+        }
+      }
+    }
+    return elem;
   }
 
   ngOnInit(): void {
+    this.updateGlobalStyles();
     this.headerInterface = this.eventService.on<string>('navigate').subscribe(e => {
       if (e === 'createQuestion') {
         this.openCreateDialog();
       } else if (e === 'topicCloudConfig') {
         this.configurationOpen = !this.configurationOpen;
-        this.demoToggle();
+        this.dataManager.demoActive = !this.dataManager.demoActive;
       } else if (e === 'topicCloudAdministration') {
         this.dialog.open(TopicCloudAdministrationComponent, {
           minWidth: '50%'
         });
       }
     });
+    this.dataManager.getData().subscribe(_ => {
+      this.rebuildData();
+    });
+    this.dataManager.getMetaData().subscribe(data => {
+      this.eventService.broadcast('tagCloudHeaderDataOverview', data);
+    });
     this.authenticationService.watchUser.subscribe(newUser => {
       if (newUser) {
         this.user = newUser;
@@ -240,21 +237,13 @@ export class TagCloudComponent implements OnInit, AfterViewInit, OnDestroy {
       });
     });
     this.translateService.use(localStorage.getItem('currentLang'));
-    this.commentService.getFilteredComments(this.roomId).subscribe((comments: Comment[]) => {
-      this.analyse(comments);
-    });
-    this.themeService.getTheme().subscribe(() => {
+    this.themeSubscription = this.themeService.getTheme().subscribe(() => {
       if (this.child) {
         setTimeout(() => {
-          this.setCloudParameters(this.getCurrentCloudParameters(), false);
+          this.setCloudParameters(TagCloudComponent.getCurrentCloudParameters(), false);
         }, 1);
       }
     });
-    this.wsCommentService.getCommentStream(this.roomId).subscribe(e => {
-      this.commentService.getFilteredComments(this.roomId).subscribe((oldComments: Comment[]) => {
-        this.analyse(oldComments);
-      });
-    });
   }
 
   ngAfterViewInit() {
@@ -263,132 +252,101 @@ export class TagCloudComponent implements OnInit, AfterViewInit, OnDestroy {
 
   ngOnDestroy() {
     document.getElementById('footer_rescale').style.display = 'block';
+    this.headerInterface.unsubscribe();
+    this.themeSubscription.unsubscribe();
+    this.dataManager.deactivate();
   }
 
   initTagCloud() {
+    this.dataManager.activate(this.roomId);
+    this.dataManager.updateDemoData(this.translateService);
+    this.setCloudParameters(TagCloudComponent.getCurrentCloudParameters(), false);
     setTimeout(() => {
-      this.setCloudParameters(this.getCurrentCloudParameters(), false);
+      this.redraw();
     });
   }
 
-  resetColorsToTheme() {
-    this.setCloudParameters(getDefaultCloudParameters());
+  get tagCloudDataManager(): TagCloudDataManager {
+    return this.dataManager;
   }
 
-  getCurrentCloudParameters(): CloudParameters {
-    const jsonData = localStorage.getItem('tagCloudConfiguration');
-    const elem: CloudParameters = jsonData != null ? JSON.parse(jsonData) : null;
-    return elem || getDefaultCloudParameters();
+  get currentCloudParameters(): CloudParameters {
+    return cloneParameters(this._currentSettings);
   }
 
-  setCloudParameters(data: CloudParameters, save = true): void {
-    const arr = [data.fontColor, ...data.cloudWeightColor, data.backgroundColor];
-    const fontRange = (data.fontSizeMax - data.fontSizeMin) / 10;
-    const styles = arr.map((e, i) => {
-      if (i > 10) {
-        return 'background-color: ' + e + ';';
-      } else if (i > 0) {
-        return 'color: ' + e + '; font-size: ' + (data.fontSizeMin + fontRange * i).toFixed(0) + '%;';
-      } else {
-        return 'color: ' + e + ';';
+  setCloudParameters(parameters: CloudParameters, save = true): void {
+    parameters = cloneParameters(parameters);
+    const updateIntensity = this.calcUpdateIntensity(parameters);
+    this._currentSettings = parameters;
+    this.zoomOnHoverOptions.delay = parameters.hoverDelay;
+    this.zoomOnHoverOptions.scale = parameters.hoverScale;
+    this.zoomOnHoverOptions.transitionTime = parameters.hoverTime;
+    if (updateIntensity >= 1) {
+      this.updateGlobalStyles();
+    }
+    if (updateIntensity >= 2) {
+      if (!this.dataManager.updateConfig(parameters)) {
+        this.rebuildData();
       }
-    });
-    setGlobalStyles(styles as TagCloudStyleData);
-    this.zoomOnHoverOptions.delay = data.hoverDelay;
-    this.zoomOnHoverOptions.scale = data.hoverScale;
-    this.zoomOnHoverOptions.transitionTime = data.hoverTime;
-    this.options.delay = data.delayWord;
-    this.randomizeAngle = data.randomAngles;
-    this.dataSize = data.cloudWeightCount;
-    this.rebuildData();
-    this.updateTagCloud();
+    }
     if (save) {
-      localStorage.setItem('tagCloudConfiguration', JSON.stringify(data));
+      localStorage.setItem('tagCloudConfiguration', JSON.stringify(parameters));
     }
   }
 
+  resetColorsToTheme() {
+    this.setCloudParameters(getDefaultCloudParameters());
+  }
+
+
   onResize(event: UIEvent): any {
     this.updateTagCloud();
   }
 
-  sortPositionsAlphabetically(sort: boolean): void {
-    if (!sort) {
-      this.sorted = false;
-      this.data.forEach(e => e.position = null);
-      return;
-    }
-    this.sorted = true;
-    if (!this.data.length) {
-      return;
+  rebuildData() {
+    const newElements = [];
+    const data = this.dataManager.currentData;
+    const countFiler = [];
+    for (let i = 0; i < 10; i++) {
+      countFiler.push(this._currentSettings.cloudWeightSettings[i].maxVisibleElements);
     }
-    this.data.sort((a, b) => a.text.localeCompare(b.text));
-    const lines = Math.floor(Math.sqrt(this.data.length - 1) + 1);
-    const divided = Math.floor(this.data.length / lines);
-    let remainder = this.data.length - divided * lines;
-    for (let i = 0, line = 0; line < lines; line++) {
-      const size = divided + (--remainder >= 0 ? 1 : 0);
-      for (let k = 0; k < size; k++, i++) {
-        this.data[i].position = new CustomPosition((k + 1) / (size + 1), (line + 1) / (lines + 1));
+    for (const [tag, tagData] of data) {
+      const amount = this.dataManager.demoActive ? 10 - tagData.adjustedWeight : 1;
+      for (let i = 0; i < amount; i++) {
+        const remaining = countFiler[tagData.adjustedWeight];
+        if (remaining !== 0) {
+          if (remaining > 0) {
+            --countFiler[tagData.adjustedWeight];
+          }
+          let rotation = this._currentSettings.cloudWeightSettings[tagData.adjustedWeight].rotation;
+          if (rotation === null || this._currentSettings.randomAngles) {
+            rotation = Math.floor(Math.random() * 30 - 15);
+          }
+          newElements.push(new TagComment(null, true, null, null, rotation, tag, 'TODO', tagData.weight));
+        }
       }
     }
-  }
-
-  analyse(comments: Comment[]) {
-    const commentsConcatenated = comments.map(c => c.body).join(' ');
-    const userSet = new Set<number>();
-    comments.forEach(comment => {
-      userSet.add(comment.userNumber);
-    });
-
-    this.spacyService.analyse(commentsConcatenated, 'de').subscribe((res: Result) => {
-      const map = new Map<string, number>();
-      res.words.filter(w => ['NE', 'NN', 'NMP', 'NNE'].indexOf(w.tag) >= 0).forEach(elem => {
-        const count = (map.get(elem.text) || 0) + 1;
-        map.set(elem.text, count);
-      });
-      this.eventService.broadcast('tagCloudHeaderDataOverview', {
-        commentCount: comments.length,
-        userCount: userSet.size,
-        tagCount: map.size
-      } as TagCloudHeaderDataOverview);
-      this.data.length = 0;
-      map.forEach((val, key) => {
-        this.data.push(new TagComment(null,
-          true, null, null,
-          this.randomizeAngle ? Math.floor(Math.random() * 30 - 15) : 0, key,
-          'TODO', val));
+    if (this._currentSettings.sortAlphabetically) {
+      const lines = Math.floor(Math.sqrt(newElements.length - 1) + 1);
+      const divided = Math.floor(newElements.length / lines);
+      let remainder = newElements.length - divided * lines;
+      for (let i = 0, line = 0; line < lines; line++) {
+        const size = divided + (--remainder >= 0 ? 1 : 0);
+        for (let k = 0; k < size; k++, i++) {
+          newElements[i].position = new CustomPosition((k + 1) / (size + 1), (line + 1) / (lines + 1));
+        }
       }
-      );
-      this.sortPositionsAlphabetically(this.sorted);
-      this.updateTagCloud();
-    });
-  }
-
-  rebuildData() {
-    if (this.randomizeAngle) {
-      this.data.forEach(e => e.rotate = Math.floor(Math.random() * 30 - 15));
-    } else {
-      this.data.forEach(e => e.rotate = 0);
     }
-    //TODO Sort using votes and keys
+    this.data = newElements;
+    setTimeout(() => {
+      this.updateTagCloud(true);
+    }, 2);
   }
 
-  updateTagCloud() {
-    let oldData = [].concat(this.data);
-
-    if (this.isDemo) {
-      this.data = [];
-      demoMap.forEach((val, key) => {
-        this.data.push(new TagComment(null,
-          true, null, null,
-          this.randomizeAngle ? Math.floor(Math.random() * 30 - 15) : 0, key,
-          'TODO', val));
-      });
-    }
-
+  updateTagCloud(dataUpdated = false) {
     this.isLoading = true;
-    if (this.sorted && this.data.length) {
-      if (!this.child.cloudDataHtmlElements || !this.child.cloudDataHtmlElements.length) {
+    if (this._currentSettings.sortAlphabetically && this.data.length) {
+      if (dataUpdated || !this.child.cloudDataHtmlElements || !this.child.cloudDataHtmlElements.length) {
         this.child.reDraw();
       }
       const width = this.child.calculatedWidth;
@@ -459,6 +417,9 @@ export class TagCloudComponent implements OnInit, AfterViewInit, OnDestroy {
   }
 
   private redraw(): void {
+    if (this.child === undefined) {
+      return;
+    }
     this.lastDebounceTime = new Date().getTime();
     this.child.reDraw();
     this.isLoading = false;
@@ -470,13 +431,80 @@ export class TagCloudComponent implements OnInit, AfterViewInit, OnDestroy {
     });
   }
 
-  public demoToggle() {
-    if (this.isDemo) {
-      this.data = [].concat(this.oldCloudData);
-    } else {
-      this.oldCloudData = [].concat(this.data);
+  private updateGlobalStyles(): void {
+    let customTagCloudStyles = document.getElementById('tagCloudStyles') as HTMLStyleElement;
+    if (!customTagCloudStyles) {
+      customTagCloudStyles = document.createElement('style');
+      customTagCloudStyles.id = 'tagCloudStyles';
+      document.head.appendChild(customTagCloudStyles);
     }
-    this.isDemo = !this.isDemo;
-    this.updateTagCloud();
+    const rules = customTagCloudStyles.sheet.cssRules;
+    for (let i = rules.length - 1; i >= 0; i--) {
+      customTagCloudStyles.sheet.deleteRule(i);
+    }
+    let textTransform = '';
+    if (this._currentSettings.textTransform === CloudTextStyle.capitalized) {
+      textTransform = 'text-transform: uppercase;';
+    } else if (this._currentSettings.textTransform === CloudTextStyle.lowercase) {
+      textTransform = 'text-transform: lowercase;';
+    }
+    const fontRange = (this._currentSettings.fontSizeMax - this._currentSettings.fontSizeMin) / 10;
+    for (let i = 1; i <= 10; i++) {
+      customTagCloudStyles.sheet.insertRule('.spacyTagCloud > span.w' + i +
+        ', .spacyTagCloud > span.w' + i + ' > a { '
+        + 'color: ' + this._currentSettings.cloudWeightSettings[i - 1].color + ';' +
+        textTransform + ' font-size: ' +
+        (this._currentSettings.fontSizeMin + fontRange * i).toFixed(0) + '%; }', rules.length);
+    }
+    customTagCloudStyles.sheet.insertRule('.spacyTagCloud > span:hover, .spacyTagCloud > span:hover > a { color: ' +
+      this._currentSettings.fontColor + '; }', rules.length);
+    customTagCloudStyles.sheet.insertRule('.spacyTagCloudContainer { background-color: ' +
+      this._currentSettings.backgroundColor + '; }', rules.length);
   }
+
+  /**
+   * 0 = update nothing,
+   * 1 = update css,
+   * 2 = update data
+   */
+  private calcUpdateIntensity(parameters: CloudParameters): number {
+    if (!this._currentSettings) {
+      return 2;
+    }
+    /*
+    hoverScale, hoverTime, hoverDelay, delayWord can be updated without refreshing
+     */
+    const cssUpdates = ['backgroundColor', 'fontColor', 'fontSizeMin', 'fontSizeMax', 'textTransform'];
+    const dataUpdates = ['randomAngles', 'sortAlphabetically', 'checkSpelling'];
+    const cssWeightUpdates = ['color'];
+    const dataWeightUpdates = ['maxVisibleElements', 'rotation'];
+    //data updates
+    for (const key of dataUpdates) {
+      if (this._currentSettings[key] !== parameters[key]) {
+        return 2;
+      }
+    }
+    for (let i = 0; i < 10; i++) {
+      for (const key of dataWeightUpdates) {
+        if (this._currentSettings.cloudWeightSettings[i][key] !== parameters.cloudWeightSettings[i][key]) {
+          return 2;
+        }
+      }
+    }
+    //css updates
+    for (const key of cssUpdates) {
+      if (this._currentSettings[key] !== parameters[key]) {
+        return 1;
+      }
+    }
+    for (let i = 0; i < 10; i++) {
+      for (const key of cssWeightUpdates) {
+        if (this._currentSettings.cloudWeightSettings[i][key] !== parameters.cloudWeightSettings[i][key]) {
+          return 1;
+        }
+      }
+    }
+    return 0;
+  }
+
 }
diff --git a/src/app/components/shared/tag-cloud/tag-cloud.data-manager.ts b/src/app/components/shared/tag-cloud/tag-cloud.data-manager.ts
new file mode 100644
index 0000000000000000000000000000000000000000..79ebcc754954ed89cf5588130404db354de193e0
--- /dev/null
+++ b/src/app/components/shared/tag-cloud/tag-cloud.data-manager.ts
@@ -0,0 +1,295 @@
+import { Comment } from '../../../models/comment';
+import { Observable, Subject } from 'rxjs';
+import { WsCommentServiceService } from '../../../services/websockets/ws-comment-service.service';
+import { CommentService } from '../../../services/http/comment.service';
+import { CloudParameters } from './tag-cloud.interface';
+import { TranslateService } from '@ngx-translate/core';
+
+export interface TagCloudDataTagEntry {
+  weight: number;
+  adjustedWeight: number;
+  cachedVoteCount: number;
+  comments: Comment[];
+}
+
+export interface TagCloudMetaData {
+  commentCount: number;
+  userCount: number;
+  tagCount: number;
+  minWeight: number;
+  maxWeight: number;
+  countPerWeight: TagCloudMetaDataCount;
+}
+
+/**
+ * The key is a generated tag (out of all comments).
+ */
+export type TagCloudData = Map<string, TagCloudDataTagEntry>;
+
+export type TagCloudMetaDataCount = [
+  number, // w1
+  number, // w2
+  number, // w3
+  number, // w4
+  number, // w5
+  number, // w6
+  number, // w7
+  number, // w8
+  number, // w9
+  number  // w10
+];
+
+export enum TagCloudDataSupplyType {
+  fullText,
+  keywords,
+  keywordsAndFullText
+}
+
+export enum TagCloudCalcWeightType {
+  byLength,
+  byVotes,
+  byLengthAndVotes
+}
+
+export class TagCloudDataManager {
+  private _isDemoActive: boolean;
+  private _isAlphabeticallySorted: boolean;
+  private _dataBus: Subject<TagCloudData>;
+  private _metaDataBus: Subject<TagCloudMetaData>;
+  private _cachedData: TagCloudData;
+  private _wsCommentSubscription = null;
+  private _roomId = null;
+  private _supplyType = TagCloudDataSupplyType.keywordsAndFullText;
+  private _calcWeightType = TagCloudCalcWeightType.byLength;
+  private _lastFetchedData: TagCloudData = null;
+  private _lastFetchedComments: Comment[] = null;
+  private _lastMetaData: TagCloudMetaData = null;
+  private readonly _currentMetaData: TagCloudMetaData;
+  private _demoData: TagCloudData = null;
+
+  constructor(private _wsCommentService: WsCommentServiceService,
+              private _commentService: CommentService) {
+    this._isDemoActive = false;
+    this._isAlphabeticallySorted = false;
+    this._dataBus = new Subject<TagCloudData>();
+    this._currentMetaData = {
+      tagCount: 0,
+      commentCount: 0,
+      userCount: 0,
+      minWeight: 0,
+      maxWeight: 0,
+      countPerWeight: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
+    };
+    this._metaDataBus = new Subject<TagCloudMetaData>();
+    this._cachedData = null;
+    // Subscribe to own 'service' for caching
+    this._dataBus.asObservable().subscribe(data => {
+      this._cachedData = data;
+    });
+  }
+
+  activate(roomId: string): void {
+    if (this._wsCommentSubscription !== null) {
+      console.error('Tag cloud data manager was already activated!');
+      return;
+    }
+    this._roomId = roomId;
+    this.onUpdateData();
+    this._wsCommentSubscription = this._wsCommentService
+      .getCommentStream(this._roomId).subscribe(e => this.onUpdateData());
+  }
+
+  deactivate(): void {
+    if (this._wsCommentSubscription === null) {
+      console.error('Tag cloud data manager was already deactivated!');
+      return;
+    }
+    this._wsCommentSubscription.unsubscribe();
+    this._wsCommentSubscription = null;
+  }
+
+  updateDemoData(translate: TranslateService): void {
+    translate.get('tag-cloud.demo-data-topic').subscribe(text => {
+      this._demoData = new Map<string, TagCloudDataTagEntry>();
+      for (let i = 10; i >= 1; i--) {
+        this._demoData.set(text.replace('%d', '' + i), {
+          cachedVoteCount: 0,
+          comments: [],
+          weight: i,
+          adjustedWeight: i - 1
+        });
+      }
+    });
+  }
+
+  get metaData(): TagCloudMetaData {
+    return this._currentMetaData;
+  }
+
+  get currentData(): TagCloudData {
+    return this._cachedData;
+  }
+
+  get dataSupplyType(): TagCloudDataSupplyType {
+    return this._supplyType;
+  }
+
+  set dataSupplyType(type: TagCloudDataSupplyType) {
+    if (this._supplyType !== type) {
+      this._supplyType = type;
+      this.rebuildTagData();
+    }
+  }
+
+  set weightCalcType(type: TagCloudCalcWeightType) {
+    if (type !== this._calcWeightType) {
+      this._calcWeightType = type;
+      this.rebuildTagData();
+    }
+  }
+
+  get weightCalcType(): TagCloudCalcWeightType {
+    return this._calcWeightType;
+  }
+
+  get demoActive(): boolean {
+    return this._isDemoActive;
+  }
+
+  set demoActive(active: boolean) {
+    if (active !== this._isDemoActive) {
+      this._isDemoActive = active;
+      if (this._isDemoActive) {
+        this._lastMetaData = {
+          ...this._currentMetaData,
+          countPerWeight: [...this._currentMetaData.countPerWeight]
+        };
+        this._currentMetaData.minWeight = 1;
+        this._currentMetaData.maxWeight = 10;
+        this._currentMetaData.countPerWeight = [10, 9, 8, 7, 6, 5, 4, 3, 2, 1];
+      } else if (this._lastMetaData !== null) {
+        for (const key of Object.keys(this._lastMetaData)) {
+          this._currentMetaData[key] = this._lastMetaData[key];
+        }
+        this._lastMetaData = null;
+      }
+      this.reformatData();
+    }
+  }
+
+  get alphabeticallySorted(): boolean {
+    return this._isAlphabeticallySorted;
+  }
+
+  updateConfig(parameters: CloudParameters): boolean {
+    if (parameters.sortAlphabetically !== this._isAlphabeticallySorted) {
+      this._isAlphabeticallySorted = parameters.sortAlphabetically;
+      this.reformatData();
+      return true;
+    }
+    return false;
+  }
+
+  getData(): Observable<TagCloudData> {
+    return this._dataBus.asObservable();
+  }
+
+  getMetaData(): Observable<TagCloudMetaData> {
+    return this._metaDataBus.asObservable();
+  }
+
+  reformatData(): void {
+    const current = this.getCurrentData();
+    if (!current) {
+      console.error('Got no data for tag cloud!');
+      return;
+    }
+    let newData: TagCloudData;
+    //TODO SORT
+    if (this._isAlphabeticallySorted) {
+      newData = new Map<string, TagCloudDataTagEntry>([...current]
+        .sort(([aTag], [bTag]) => aTag.localeCompare(bTag)));
+    } else {
+      newData = new Map<string, TagCloudDataTagEntry>([...current]
+        .sort(([_, aTagData], [__, bTagData]) => bTagData.weight - aTagData.weight));
+    }
+    //TODO APPLY OTHER
+    this._dataBus.next(newData);
+  }
+
+  private getCurrentData(): TagCloudData {
+    if (this._isDemoActive) {
+      return this._demoData;
+    }
+    return this._lastFetchedData;
+  }
+
+  private onUpdateData(): void {
+    this._commentService.getFilteredComments(this._roomId).subscribe((comments: Comment[]) => {
+      this._lastFetchedComments = comments;
+      if (this._isDemoActive) {
+        this._lastMetaData.commentCount = comments.length;
+      } else {
+        this._currentMetaData.commentCount = comments.length;
+      }
+      this.rebuildTagData();
+    });
+  }
+
+  private calculateWeight(tagData: TagCloudDataTagEntry): number {
+    switch (this._calcWeightType) {
+      case TagCloudCalcWeightType.byVotes:
+        return tagData.cachedVoteCount;
+      case TagCloudCalcWeightType.byLengthAndVotes:
+        return tagData.cachedVoteCount / 10.0 + tagData.comments.length;
+      default:
+        return tagData.comments.length;
+    }
+  }
+
+  private rebuildTagData() {
+    const currentMeta = this._isDemoActive ? this._lastMetaData : this._currentMetaData;
+    const data: TagCloudData = new Map<string, TagCloudDataTagEntry>();
+    const users = new Set<number>();
+    for (const comment of this._lastFetchedComments) {
+      //TODO Check supply types
+      let keywords = comment.keywords || [];
+      for (const keyword of keywords) {
+        //TODO Check spelling
+        let current = data.get(keyword);
+        if (current === undefined) {
+          current = {cachedVoteCount: 0, comments: [], weight: 0, adjustedWeight: 0};
+          data.set(keyword, current);
+        }
+        current.cachedVoteCount += comment.score;
+        current.comments.push(comment);
+      }
+      users.add(comment.userNumber);
+    }
+    let minWeight = null;
+    let maxWeight = null;
+    for (const value of data.values()) {
+      value.weight = this.calculateWeight(value);
+      minWeight = Math.min(value.weight, minWeight || value.weight);
+      maxWeight = Math.max(value.weight, maxWeight || value.weight);
+    }
+    //calculate weight counts and adjusted weights
+    const same = minWeight === maxWeight;
+    const span = maxWeight - minWeight;
+    currentMeta.countPerWeight = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
+    for (const value of data.values()) {
+      value.adjustedWeight = same ? 4 : Math.round((value.weight - minWeight) * 9.0 / span);
+      ++currentMeta.countPerWeight[value.adjustedWeight];
+    }
+    this._lastFetchedData = data;
+    currentMeta.tagCount = data.size;
+    currentMeta.userCount = users.size;
+    currentMeta.minWeight = minWeight;
+    currentMeta.maxWeight = maxWeight;
+    this._metaDataBus.next(currentMeta);
+    if (!this._isDemoActive) {
+      this.reformatData();
+    }
+  }
+
+}
diff --git a/src/app/components/shared/tag-cloud/tag-cloud.interface.ts b/src/app/components/shared/tag-cloud/tag-cloud.interface.ts
index b7dfb7ecfb2ae5378e981acb0cb4e6470ebbf34a..ca84784ddeec0566a7f302f303831c87aa7c5415 100644
--- a/src/app/components/shared/tag-cloud/tag-cloud.interface.ts
+++ b/src/app/components/shared/tag-cloud/tag-cloud.interface.ts
@@ -1,34 +1,40 @@
-export interface TagCloudHeaderDataOverview {
-  commentCount: number;
-  userCount: number;
-  tagCount: number;
+export interface CloudWeightSetting {
+  /**
+   * This field specifies how many elements of this weight are displayed.
+   *
+   * A number less than zero means that all elements of the weight are displayed.
+   */
+  maxVisibleElements: number;
+  /**
+   * CSS color property value.
+   */
+  color: string;
+  /**
+   * Rotation of each html element in degrees.
+   *
+   * null indicates random rotation.
+   */
+  rotation: number;
 }
 
-export type CloudWeightCount = [
-  number, // w1
-  number, // w2
-  number, // w3
-  number, // w4
-  number, // w5
-  number, // w6
-  number, // w7
-  number, // w8
-  number, // w9
-  number // w10
+export type CloudWeightSettings = [
+  CloudWeightSetting, // w1
+  CloudWeightSetting, // w2
+  CloudWeightSetting, // w3
+  CloudWeightSetting, // w4
+  CloudWeightSetting, // w5
+  CloudWeightSetting, // w6
+  CloudWeightSetting, // w7
+  CloudWeightSetting, // w8
+  CloudWeightSetting, // w9
+  CloudWeightSetting  // w10
 ];
 
-export type CloudWeightColor = [
-  string, // w1
-  string, // w2
-  string, // w3
-  string, // w4
-  string, // w5
-  string, // w6
-  string, // w7
-  string, // w8
-  string, // w9
-  string // w10
-];
+export enum CloudTextStyle {
+  normal,
+  lowercase,
+  capitalized
+}
 
 export interface CloudParameters {
   /**
@@ -68,13 +74,38 @@ export interface CloudParameters {
    */
   randomAngles: boolean;
   /**
-   * The count of cloud weights is used to limit the size of the displayed weighted elements.
-   *
-   * A number less than zero means that all elements of the weight are displayed.
+   * Sorts the cloud alphabetical.
+   */
+  sortAlphabetically: boolean;
+  /**
+   * Checks if the word is spelled correctly, if not, do not display it.
    */
-  cloudWeightCount: CloudWeightCount;
+  checkSpelling: boolean;
   /**
-   * This array contains the CSS color property for each cloud weight
+   * Custom CSS text transform setting
    */
-  cloudWeightColor: CloudWeightColor;
+  textTransform: CloudTextStyle;
+  /**
+   * Array of settings for each weight group.
+   */
+  cloudWeightSettings: CloudWeightSettings;
 }
+
+const clone = (elem: any): any => {
+  if (Array.isArray(elem)) {
+    const copy = new Array(elem.length);
+    for (let i = 0; i < elem.length; i++) {
+      copy[i] = clone(elem[i]);
+    }
+    return copy;
+  } else if (elem instanceof Object) {
+    const copy = {};
+    for (const key of Object.keys(elem)) {
+      copy[key] = clone(elem[key]);
+    }
+    return copy;
+  }
+  return elem;
+};
+
+export const cloneParameters = (parameters: CloudParameters) => clone(parameters);
diff --git a/src/app/services/http/comment.service.ts b/src/app/services/http/comment.service.ts
index e664bfec77b74d00626e41124d1560c1101f1835..66ab1d529173dc3a6a5109e0bceba6970de095f3 100644
--- a/src/app/services/http/comment.service.ts
+++ b/src/app/services/http/comment.service.ts
@@ -109,7 +109,12 @@ export class CommentService extends BaseHttpService {
       externalFilters: {}
     }, httpOptions).pipe(
       map(commentList => {
-        return commentList.map(comment => this.parseUserNumber(comment));
+        return commentList.map(comment => {
+          const newComment = this.parseUserNumber(comment);
+          // @ts-ignore
+          newComment.keywords = JSON.parse(newComment.keywords as string);
+          return newComment;
+        });
       }),
       tap(_ => ''),
       catchError(this.handleError<Comment[]>('getComments', []))
@@ -238,4 +243,4 @@ export class CommentService extends BaseHttpService {
     hash = +userNumberString.substring(userNumberString.length - 4, userNumberString.length);
     return hash;
   }
-}
\ No newline at end of file
+}
diff --git a/src/assets/i18n/creator/de.json b/src/assets/i18n/creator/de.json
index 348dfe6fbb8ae6317c92664965dabca116f76229..fdee800adcf2f7b2a9d15dcb3994b2974c33ad84 100644
--- a/src/assets/i18n/creator/de.json
+++ b/src/assets/i18n/creator/de.json
@@ -369,6 +369,22 @@
     "weight-color": "Schriftfarbe",
     "weight-number": "max. Anzahl Schlüsselwörter",
     "weight-color-tooltip": "Auswahl der Schriftfarbe",
-    "weight-number-tooltip": "maximale Anzahl der Schlüsselwörter festlegen"
+    "weight-number-tooltip": "maximale Anzahl der Schlüsselwörter festlegen",
+    "automatic-spelling": "Automatische Rechtschreibung",
+    "notation": "Notation:",
+    "lowerCase": "Kleinschreibung",
+    "capitalization": "Großschreibung",
+    "standard": "Standard",
+    "alphabetical-sorting": "Alphabetische Sortierung",
+    "cleanUpView": "Tag-Cleanup Einstellungen",
+    "rotation": "Drehgrad zufälliger Einträge",
+    "highestWeight": "Anzahl Tags mit max. Gewichtung",
+    "automatic-spelling-tooltip": "automatische Überprüfung der Rechtschreibung",
+    "notation-tooltip": "Einstellung der Schreibweise: klein, groß, standard",
+    "alphabetical-sorting-tooltip": "Alphabetische Sortierung",
+    "rotation-tooltip": "Einige Einträge zufällig um x Grad drehen",
+    "highestWeight-tooltip": "x Tags mit der höchsten Gewichtung anzeigen",
+    "rotate-weight": "Einige Einträge dieser Gewichtsklasse zufällig um x Grad drehen",
+    "rotate-weight-tooltip": "Einige zufällig ausgewählte Einträge um diesen Winkel drehen"
   }
 }
diff --git a/src/assets/i18n/creator/en.json b/src/assets/i18n/creator/en.json
index 5eaee11f33629fea3ad5f4790b6fda2275ea6c20..94f74155d652f514048758b322e62c86835e5cad 100644
--- a/src/assets/i18n/creator/en.json
+++ b/src/assets/i18n/creator/en.json
@@ -370,6 +370,22 @@
     "weight-color": "Font color",
     "weight-number": "max. number of keywords",
     "weight-color-tooltip": "select font-color",
-    "weight-number-tooltip": "select maximal number of keywords"
+    "weight-number-tooltip": "select maximal number of keywords",
+    "automatic-spelling": "Automatic spelling",
+    "notation": "Notation:",
+    "lowerCase": "Lower case",
+    "capitalization": "Capitalization",
+    "standard": "Standard",
+    "alphabetical-sorting": "Alphabetical sorting",
+    "cleanUpView": "Tag-Cleanup Settings",
+    "rotation": "rotation of random entries",
+    "highestWeight": "Number of tags with highest weight",
+    "automatic-spelling-tooltip": "automatic spelling check",
+    "notation-tooltip": "Notation-Settings: small, large, standard",
+    "alphabetical-sorting-tooltip": "Alphabetical sorting",
+    "rotation-tooltip": "rotate some entries randomly by x degrees",
+    "highestWeight-tooltip": "show x tags with the highest weight",
+    "rotate-weight": "Rotate some entries of this weight class randomly by x degrees",
+    "rotate-weight-tooltip": "Rotate some randomly selected entries by this angle"
   }
 }
diff --git a/src/assets/i18n/participant/de.json b/src/assets/i18n/participant/de.json
index f82fa30c7e299e1c96e95d9223eef07e1871b3ae..2e2cbf6e70311e9a35b63573be254bb03fbc3968 100644
--- a/src/assets/i18n/participant/de.json
+++ b/src/assets/i18n/participant/de.json
@@ -226,7 +226,8 @@
   },
   "tag-cloud": {
     "config": "Wolkenansicht ändern",
-    "administration": "Wolkenthemen editieren"
+    "administration": "Wolkenthemen editieren",
+    "demo-data-topic": "Thema %d"
   },
   "topic-cloud-dialog": {
     "cancel": "Abbrechen",
@@ -298,6 +299,22 @@
     "weight-color": "Schriftfarbe",
     "weight-number": "max. Anzahl Schlüsselwörter",
     "weight-color-tooltip": "Auswahl der Schriftfarbe",
-    "weight-number-tooltip": "maximale Anzahl der Schlüsselwörter festlegen"
+    "weight-number-tooltip": "maximale Anzahl der Schlüsselwörter festlegen",
+    "automatic-spelling": "Automatische Rechtschreibung",
+    "notation": "Notation:",
+    "lowerCase": "Kleinschreibung",
+    "capitalization": "Großschreibung",
+    "standard": "Standard",
+    "alphabetical-sorting": "Alphabetische Sortierung",
+    "cleanUpView": "Tag-Cleanup Einstellungen",
+    "rotation": "Drehgrad zufälliger Einträge",
+    "highestWeight": "Anzahl Tags mit max. Gewichtung",
+    "automatic-spelling-tooltip": "automatische Überprüfung der Rechtschreibung",
+    "notation-tooltip": "Einstellung der Schreibweise: klein, groß, standard",
+    "alphabetical-sorting-tooltip": "Alphabetische Sortierung",
+    "rotation-tooltip": "Einige Einträge zufällig um x Grad drehen",
+    "highestWeight-tooltip": "x Tags mit der höchsten Gewichtung anzeigen",
+    "rotate-weight": "Einige Einträge dieser Gewichtsklasse zufällig um x Grad drehen",
+    "rotate-weight-tooltip": "Einige zufällig ausgewählte Einträge um diesen Winkel drehen"
   }
 }
diff --git a/src/assets/i18n/participant/en.json b/src/assets/i18n/participant/en.json
index 3383cfd16c303da8b9ce9eea5a9a59d194f82e89..8ec083e376d342e82786144bfd1447b57c48b152 100644
--- a/src/assets/i18n/participant/en.json
+++ b/src/assets/i18n/participant/en.json
@@ -231,7 +231,8 @@
   },
   "tag-cloud": {
     "config": "Modify cloud view",
-    "administration": "Edit cloud topics"
+    "administration": "Edit cloud topics",
+    "demo-data-topic": "Topic %d"
   },
   "topic-cloud-dialog":{
     "edit": "Edit",
@@ -303,6 +304,22 @@
     "weight-color": "Font color",
     "weight-number": "max. number of keywords",
     "weight-color-tooltip": "select font-color",
-    "wieght-number-tooltip": "select maximal number of keywords"
+    "wieght-number-tooltip": "select maximal number of keywords",
+    "automatic-spelling": "Automatic spelling",
+    "notation": "Notation:",
+    "lowerCase": "Lower case",
+    "capitalization": "Capitalization",
+    "standard": "Standard",
+    "alphabetical-sorting": "Alphabetical sorting",
+    "cleanUpView": "Tag-Cleanup Settings",
+    "rotation": "rotation of random entries",
+    "highestWeight": "Number of tags with highest weight",
+    "automatic-spelling-tooltip": "automatic spelling check",
+    "notation-tooltip": "Notation-Settings: small, large, standard",
+    "alphabetical-sorting-tooltip": "Alphabetical sorting",
+    "rotation-tooltip": "rotate some entries randomly by x degrees",
+    "highestWeight-tooltip": "show x tags with the highest weight",
+    "rotate-weight": "Rotate some entries of this weight class randomly by x degrees",
+    "rotate-weight-tooltip":"Rotate some randomly selected entries by this angle"
   }
 }