This is an automated email from the ASF dual-hosted git repository.

riemer pushed a commit to branch improve-data-explorer-widgets
in repository https://gitbox.apache.org/repos/asf/streampipes.git

commit 08a0b28444d2025ca073ed5cc55efd0783f22050
Author: Dominik Riemer <[email protected]>
AuthorDate: Mon Aug 28 23:02:26 2023 +0200

    Migrate heatmap widget to echarts renderer
---
 .../base-data-explorer-echarts-widget.directive.ts |  15 ++
 .../distribution-chart-widget.component.ts         |  14 --
 .../widgets/heatmap/heatmap-widget.component.html  |  53 -----
 .../widgets/heatmap/heatmap-widget.component.scss  |  32 ---
 .../widgets/heatmap/heatmap-widget.component.ts    | 265 +--------------------
 .../echarts-renderer/sp-heatmap-renderer.ts        | 104 +++++++-
 6 files changed, 127 insertions(+), 356 deletions(-)

diff --git 
a/ui/src/app/data-explorer/components/widgets/base/base-data-explorer-echarts-widget.directive.ts
 
b/ui/src/app/data-explorer/components/widgets/base/base-data-explorer-echarts-widget.directive.ts
index 7bf1e1dcb..64b440ed4 100644
--- 
a/ui/src/app/data-explorer/components/widgets/base/base-data-explorer-echarts-widget.directive.ts
+++ 
b/ui/src/app/data-explorer/components/widgets/base/base-data-explorer-echarts-widget.directive.ts
@@ -18,6 +18,7 @@
 
 import { Directive, OnInit } from '@angular/core';
 import {
+    DataExplorerField,
     DataExplorerWidgetModel,
     SpQueryResult,
 } from '@streampipes/platform-services';
@@ -97,6 +98,20 @@ export abstract class BaseDataExplorerEchartsWidgetDirective<
         };
     }
 
+    triggerFieldUpdate(
+        selected: DataExplorerField,
+        addedFields: DataExplorerField[],
+        removedFields: DataExplorerField[],
+    ): DataExplorerField {
+        return this.updateSingleField(
+            selected,
+            this.fieldProvider.numericFields,
+            addedFields,
+            removedFields,
+            field => field.fieldCharacteristics.numeric,
+        );
+    }
+
     refreshView() {
         this.renderSubject.next();
     }
diff --git 
a/ui/src/app/data-explorer/components/widgets/distribution-chart/distribution-chart-widget.component.ts
 
b/ui/src/app/data-explorer/components/widgets/distribution-chart/distribution-chart-widget.component.ts
index 98183b228..8e4ce4423 100644
--- 
a/ui/src/app/data-explorer/components/widgets/distribution-chart/distribution-chart-widget.component.ts
+++ 
b/ui/src/app/data-explorer/components/widgets/distribution-chart/distribution-chart-widget.component.ts
@@ -45,20 +45,6 @@ export class DistributionChartWidgetComponent
             );
     }
 
-    triggerFieldUpdate(
-        selected: DataExplorerField,
-        addedFields: DataExplorerField[],
-        removedFields: DataExplorerField[],
-    ): DataExplorerField {
-        return this.updateSingleField(
-            selected,
-            this.fieldProvider.numericFields,
-            addedFields,
-            removedFields,
-            field => field.fieldCharacteristics.numeric,
-        );
-    }
-
     getRenderer(): SpEchartsRenderer<DistributionChartWidgetModel> {
         const widgetCategory = DataExplorerWidgetRegistry.getWidgetTemplate(
             WidgetType.DistributionChart,
diff --git 
a/ui/src/app/data-explorer/components/widgets/heatmap/heatmap-widget.component.html
 
b/ui/src/app/data-explorer/components/widgets/heatmap/heatmap-widget.component.html
deleted file mode 100644
index cc1a8228d..000000000
--- 
a/ui/src/app/data-explorer/components/widgets/heatmap/heatmap-widget.component.html
+++ /dev/null
@@ -1,53 +0,0 @@
-<!--
-  ~ Licensed to the Apache Software Foundation (ASF) under one or more
-  ~ contributor license agreements.  See the NOTICE file distributed with
-  ~ this work for additional information regarding copyright ownership.
-  ~ The ASF licenses this file to You under the Apache License, Version 2.0
-  ~ (the "License"); you may not use this file except in compliance with
-  ~ the License.  You may obtain a copy of the License at
-  ~
-  ~    http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  ~
-  -->
-
-<div
-    fxFlex="100"
-    fxLayoutAlign="center center"
-    fxLayout="column"
-    class="main-panel"
->
-    <sp-no-data-in-date-range
-        *ngIf="showNoDataInDateRange"
-        [viewDateRange]="timeSettings"
-        class="h-100"
-    >
-    </sp-no-data-in-date-range>
-
-    <sp-too-much-data
-        [amountOfEvents]="amountOfTooMuchEvents"
-        (loadDataWithTooManyEventsEmitter)="loadDataWithTooManyEvents()"
-        *ngIf="showTooMuchData"
-        class="h-100"
-    >
-    </sp-too-much-data>
-
-    <div class="value-panel">
-        <div
-            echarts
-            [options]="option"
-            [ngStyle]="{ width: currentWidth, height: '100%' }"
-            (chartInit)="onChartInit($event)"
-            [merge]="dynamic"
-            [ngStyle]="
-                showData ? { visibility: 'visible' } : { visibility: 'hidden' }
-            "
-            *ngIf="configReady"
-        ></div>
-    </div>
-</div>
diff --git 
a/ui/src/app/data-explorer/components/widgets/heatmap/heatmap-widget.component.scss
 
b/ui/src/app/data-explorer/components/widgets/heatmap/heatmap-widget.component.scss
deleted file mode 100644
index c4239506e..000000000
--- 
a/ui/src/app/data-explorer/components/widgets/heatmap/heatmap-widget.component.scss
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-.plotly-container {
-    width: 100%;
-    align-self: start;
-    height: 100%;
-}
-
-.main-panel {
-    width: 100%;
-    height: 100%;
-    text-align: center;
-    left: 50%;
-    display: inline-grid;
-    align-content: start;
-}
diff --git 
a/ui/src/app/data-explorer/components/widgets/heatmap/heatmap-widget.component.ts
 
b/ui/src/app/data-explorer/components/widgets/heatmap/heatmap-widget.component.ts
index f6188d9db..5039553db 100644
--- 
a/ui/src/app/data-explorer/components/widgets/heatmap/heatmap-widget.component.ts
+++ 
b/ui/src/app/data-explorer/components/widgets/heatmap/heatmap-widget.component.ts
@@ -17,16 +17,12 @@
  */
 
 import { Component, OnInit } from '@angular/core';
-import {
-    DataExplorerField,
-    SpQueryResult,
-} from '@streampipes/platform-services';
+import { DataExplorerField } from '@streampipes/platform-services';
 
 import { HeatmapWidgetModel } from './model/heatmap-widget.model';
-
-import { EChartsOption } from 'echarts';
 import { BaseDataExplorerEchartsWidgetDirective } from 
'../base/base-data-explorer-echarts-widget.directive';
 import { SpEchartsRenderer } from '../../../models/dataview-dashboard.model';
+import { SpHeatmapRenderer } from 
'../../../echarts-renderer/sp-heatmap-renderer';
 
 @Component({
     selector: 'sp-data-explorer-heatmap-widget',
@@ -37,259 +33,24 @@ export class HeatmapWidgetComponent
     extends BaseDataExplorerEchartsWidgetDirective<HeatmapWidgetModel>
     implements OnInit
 {
-    dynamic: EChartsOption;
-
     ngOnInit(): void {
         super.ngOnInit();
     }
 
-    onDataReceived(spQueryResult: SpQueryResult[]) {
-        this.setShownComponents(false, true, false, false);
-        const dataBundle = this.convertData(spQueryResult);
-        if (Object.keys(this.option).length > 0) {
-            this.setOptions(
-                dataBundle[0],
-                dataBundle[1],
-                dataBundle[2],
-                dataBundle[3],
-                dataBundle[4],
-            );
-        }
-    }
-
-    convertData(spQueryResult: SpQueryResult[]) {
-        let min = 1000000;
-        let max = -100000;
-
-        const result = spQueryResult[0].allDataSeries;
-        // const xAxisData = this.transform(result[0].rows, 0);
-
-        const aggregatedXData = [];
-        result.forEach(x => {
-            const localXAxisData = this.transform(x.rows, 0);
-            aggregatedXData.push(...localXAxisData);
-        });
-
-        const xAxisData = aggregatedXData.sort();
-
-        const convXAxisData = [];
-        xAxisData.forEach(x => {
-            const date = new Date(x);
-            const size = 2;
-            const year = date.getFullYear();
-            const month = this.pad(date.getMonth() + 1, size);
-            const day = date.getDate();
-            const hours = this.pad(date.getHours(), size);
-            const minutes = this.pad(date.getMinutes(), size);
-            const seconds = this.pad(date.getSeconds(), size);
-            const milli = this.pad(date.getMilliseconds(), 3);
-
-            const strDate =
-                year +
-                '-' +
-                month +
-                '-' +
-                day +
-                ' ' +
-                hours +
-                ':' +
-                minutes +
-                ':' +
-                seconds +
-                '.' +
-                milli;
-            convXAxisData.push(strDate);
-        });
-
-        const heatIndex = this.getColumnIndex(
-            this.dataExplorerWidget.visualizationConfig.selectedHeatProperty,
-            spQueryResult[0],
-        );
-
-        const yAxisData = [];
-        const contentData = [];
-
-        result.map((groupedList, index) => {
-            let groupedVal = '';
-
-            if (groupedList['tags'] != null) {
-                Object.entries(groupedList['tags']).forEach(([key, value]) => {
-                    groupedVal = value;
-                });
-            }
-
-            yAxisData.push(groupedVal);
-
-            const contentDataPure = this.transform(
-                result[index].rows,
-                heatIndex,
-            );
-            const localMax = Math.max.apply(Math, contentDataPure);
-            const localMin = Math.min.apply(Math, contentDataPure);
-
-            max = localMax > max ? localMax : max;
-            min = localMin < min ? localMin : min;
-
-            const localXAxisData = this.transform(groupedList.rows, 0);
-
-            contentDataPure.map((cnt, colIndex) => {
-                const currentX = localXAxisData[colIndex];
-                const searchedIndex = aggregatedXData.indexOf(currentX);
-                contentData.push([searchedIndex, index, cnt]);
-            });
-        });
-
-        const timeNames = convXAxisData;
-        const groupNames = yAxisData;
-
-        this.option['tooltip'] = {
-            formatter(params) {
-                const timeIndex = params.value[0];
-                const groupNameIndex = params.value[1];
-
-                const value = params.value[2];
-                const time = timeNames[timeIndex];
-                const groupName = groupNames[groupNameIndex];
-
-                let formattedTip =
-                    '<style>' +
-                    'ul {margin: 0px; padding: 0px; list-style-type: none; 
text-align: left}' +
-                    '</style>' +
-                    '<ul>' +
-                    '<li><b>' +
-                    'Time: ' +
-                    '</b>' +
-                    time +
-                    '</li>';
-
-                if (groupName !== '') {
-                    formattedTip =
-                        formattedTip +
-                        '<li><b>' +
-                        'Group: ' +
-                        '</b>' +
-                        groupName +
-                        '</li>';
-                }
-
-                formattedTip =
-                    formattedTip +
-                    '<li><b>' +
-                    'Value: ' +
-                    '</b>' +
-                    value +
-                    '</li>' +
-                    '</ul>';
-
-                return formattedTip;
-            },
-            position: 'top',
-        };
-
-        if (groupNames.length === 1) {
-            this.option['tooltip']['position'] = (
-                point,
-                params,
-                dom,
-                rect,
-                size,
-            ) => {
-                return [point[0], '10%'];
-            };
-        }
-
-        return [contentData, convXAxisData, yAxisData, min, max];
-    }
-
-    initOptions() {
-        this.option = {
-            tooltip: {},
-            grid: {
-                height: '80%',
-                top: '7%',
-            },
-            xAxis: {
-                type: 'category',
-                data: [],
-                splitArea: {
-                    show: true,
-                },
-            },
-            yAxis: {
-                type: 'category',
-                data: [],
-                splitArea: {
-                    show: true,
-                },
-            },
-            visualMap: {
-                min: 0,
-                max: 10,
-                calculable: true,
-                orient: 'vertical',
-                right: '5%',
-                top: '7%',
-            },
-            series: [
-                {
-                    name: '',
-                    type: 'heatmap',
-                    data: [],
-                    label: {
-                        show: true,
-                    },
-                    emphasis: {
-                        itemStyle: {
-                            shadowBlur: 10,
-                            shadowColor: 'rgba(0, 0, 0, 0.5)',
-                        },
-                    },
-                },
-            ],
-        };
-    }
-
-    setOptions(
-        contentData: any,
-        xAxisData: any,
-        yAxisData: any,
-        min: any,
-        max: any,
-    ) {
-        this.dynamic = this.option;
-        this.dynamic.series[0].data = contentData;
-        this.dynamic.series[0].label.show =
-            this.dataExplorerWidget.visualizationConfig.showLabelsProperty;
-        this.dynamic['xAxis']['data'] = xAxisData;
-        this.dynamic['yAxis']['data'] = yAxisData;
-        this.dynamic['visualMap']['min'] = min;
-        this.dynamic['visualMap']['max'] = max;
-        if (this.eChartsInstance) {
-            this.eChartsInstance.setOption(this.dynamic as EChartsOption);
-        }
-        this.option = this.dynamic;
-    }
-
-    transform(rows, index: number): any[] {
-        return rows.map(row => row[index]);
-    }
-
-    pad(num, size) {
-        num = num.toString();
-        while (num.length < size) {
-            num = '0' + num;
-        }
-        return num;
-    }
-
     getRenderer(): SpEchartsRenderer<HeatmapWidgetModel> {
-        return undefined;
+        return new SpHeatmapRenderer();
     }
 
-    protected handleUpdatedFields(
+    handleUpdatedFields(
         addedFields: DataExplorerField[],
         removedFields: DataExplorerField[],
-    ) {}
-
-    refreshView() {}
+    ) {
+        this.dataExplorerWidget.visualizationConfig.selectedHeatProperty =
+            this.triggerFieldUpdate(
+                this.dataExplorerWidget.visualizationConfig
+                    .selectedHeatProperty,
+                addedFields,
+                removedFields,
+            );
+    }
 }
diff --git a/ui/src/app/data-explorer/echarts-renderer/sp-heatmap-renderer.ts 
b/ui/src/app/data-explorer/echarts-renderer/sp-heatmap-renderer.ts
index d069d63f5..5a5e05f17 100644
--- a/ui/src/app/data-explorer/echarts-renderer/sp-heatmap-renderer.ts
+++ b/ui/src/app/data-explorer/echarts-renderer/sp-heatmap-renderer.ts
@@ -18,20 +18,114 @@
 
 import { SpBaseEchartsRenderer } from './sp-base-echarts-renderer';
 import { HeatmapWidgetModel } from 
'../components/widgets/heatmap/model/heatmap-widget.model';
-import { GeneratedDataset, WidgetSize } from '../models/dataset.model';
+import { GeneratedDataset, TagValue } from '../models/dataset.model';
 import { EChartsOption } from 'echarts';
+import {
+    DimensionDefinitionLoose,
+    OptionDataValue,
+    OptionSourceDataArrayRows,
+} from 'echarts/types/src/util/types';
 
 export class SpHeatmapRenderer extends 
SpBaseEchartsRenderer<HeatmapWidgetModel> {
+    getType(): string {
+        return 'heatmap';
+    }
+
     applyOptions(
         datasets: GeneratedDataset,
         options: EChartsOption,
         widgetConfig: HeatmapWidgetModel,
-        widgetSize: WidgetSize,
     ): void {
-        // TODO
+        this.basicOptions(options);
+
+        const field = widgetConfig.visualizationConfig.selectedHeatProperty;
+        const sourceIndex = field.sourceIndex;
+
+        const rawDataset = datasets.dataset[sourceIndex];
+        const rawDatasetSource: OptionSourceDataArrayRows =
+            rawDataset.source as OptionSourceDataArrayRows;
+        const tags = datasets.tagValues[sourceIndex];
+        const heatIndex = rawDataset.dimensions.indexOf(field.fullDbName);
+        rawDatasetSource.shift();
+        rawDatasetSource.sort((a, b) => {
+            const dateA = new Date(a[0]);
+            const dateB = new Date(b[0]);
+            return dateA.getTime() - dateB.getTime();
+        });
+        const transformedDataset = (
+            rawDataset.source as OptionSourceDataArrayRows
+        ).map((row, index) => {
+            return [
+                index,
+                this.makeTag(rawDataset.dimensions, tags, row),
+                row[heatIndex],
+            ];
+        });
+
+        options.dataset = { source: transformedDataset };
+        (options.xAxis as any).data = rawDatasetSource.map(s => {
+            return new Date(s[0]).toLocaleString();
+        });
+        options.series = [
+            {
+                name: '',
+                type: 'heatmap',
+                datasetIndex: 0,
+                encode: {
+                    itemId: 0,
+                    value: heatIndex,
+                },
+                label: {
+                    show: widgetConfig.visualizationConfig.showLabelsProperty,
+                },
+                emphasis: {
+                    itemStyle: {
+                        shadowBlur: 10,
+                        shadowColor: 'rgba(0, 0, 0, 0.5)',
+                    },
+                },
+            },
+        ];
     }
 
-    getType(): string {
-        return 'heatmap';
+    basicOptions(options: EChartsOption): void {
+        options.tooltip = {};
+        options.grid = {
+            height: '80%',
+            top: '80',
+        };
+        options.xAxis = {
+            type: 'category',
+            splitArea: {
+                show: true,
+            },
+        };
+        options.yAxis = {
+            type: 'category',
+            splitArea: {
+                show: true,
+            },
+        };
+        options.visualMap = {
+            calculable: true,
+            orient: 'horizontal',
+            right: '5%',
+            top: '20',
+        };
+    }
+
+    private makeTag(
+        dimensions: DimensionDefinitionLoose[],
+        tags: TagValue[],
+        row: Array<OptionDataValue>,
+    ) {
+        if (tags.length > 0) {
+            const rowValues = [];
+            tags[0].tagKeys.forEach(key => {
+                const index = dimensions.indexOf(key);
+                rowValues.push(row[index]);
+            });
+            return rowValues.toString();
+        }
     }
 }

Reply via email to