From 1bd678851632bbbb302363574eb5e3e19dc343e9 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Fri, 29 Mar 2019 13:18:35 -0400
Subject: reorganized and mostly working northstar histograms.

---
 .../dash-nodes/HistogramLabelPrimitives.tsx        | 78 ++++++++++++++++++++++
 1 file changed, 78 insertions(+)
 create mode 100644 src/client/northstar/dash-nodes/HistogramLabelPrimitives.tsx

(limited to 'src/client/northstar/dash-nodes/HistogramLabelPrimitives.tsx')

diff --git a/src/client/northstar/dash-nodes/HistogramLabelPrimitives.tsx b/src/client/northstar/dash-nodes/HistogramLabelPrimitives.tsx
new file mode 100644
index 000000000..45b23874d
--- /dev/null
+++ b/src/client/northstar/dash-nodes/HistogramLabelPrimitives.tsx
@@ -0,0 +1,78 @@
+import React = require("react")
+import { action, computed, reaction } from "mobx";
+import { observer } from "mobx-react";
+import { Utils as DashUtils } from '../../../Utils';
+import { NominalVisualBinRange } from "../model/binRanges/NominalVisualBinRange";
+import "../utils/Extensions";
+import { StyleConstants } from "../utils/StyleContants";
+import { HistogramBox, HistogramPrimitivesProps } from "./HistogramBox";
+import "./HistogramLabelPrimitives.scss";
+
+@observer
+export class HistogramLabelPrimitives extends React.Component<HistogramPrimitivesProps> {
+    componentDidMount() {
+        reaction(() => [this.props.HistoBox.PanelWidth, this.props.HistoBox.SizeConverter.LeftOffset, this.props.HistoBox.VisualBinRanges.length],
+            (fields) => HistogramLabelPrimitives.computeLabelAngle(fields[0] as number, fields[1] as number, this.props.HistoBox), { fireImmediately: true });
+    }
+
+    @action
+    static computeLabelAngle(panelWidth: number, leftOffset: number, histoBox: HistogramBox) {
+        const textWidth = 30;
+        if (panelWidth > 0 && histoBox.VisualBinRanges.length && histoBox.VisualBinRanges[0] instanceof NominalVisualBinRange) {
+            let space = (panelWidth - leftOffset * 2) / histoBox.VisualBinRanges[0].GetBins().length;
+            histoBox.SizeConverter.SetLabelAngle(Math.min(Math.PI / 2, Math.max(Math.PI / 6, textWidth / space * Math.PI / 2)));
+        } else if (histoBox.SizeConverter.LabelAngle) {
+            histoBox.SizeConverter.SetLabelAngle(0);
+        }
+    }
+    @computed get xaxislines() { return this.renderGridLinesAndLabels(0); }
+    @computed get yaxislines() { return this.renderGridLinesAndLabels(1); }
+
+    private renderGridLinesAndLabels(axis: number) {
+        let sc = this.props.HistoBox.SizeConverter;
+        let vb = this.props.HistoBox.VisualBinRanges;
+        if (!vb.length || !sc.Initialized)
+            return (null);
+        let dim = (axis == 0 ? this.props.HistoBox.PanelWidth : this.props.HistoBox.PanelHeight) / ((axis == 0 && vb[axis] instanceof NominalVisualBinRange) ?
+            (12 + 5) : //  (<number>FontStyles.AxisLabel.fontSize + 5)));
+            sc.MaxLabelSizes[axis].coords[axis] + 5);
+
+        let labels = vb[axis].GetLabels();
+        return labels.reduce((prims, binLabel, i) => {
+            let r = sc.DataToScreenRange(binLabel.minValue!, binLabel.maxValue!, axis);
+            if (i % Math.ceil(labels.length / dim) === 0 && binLabel.label) {
+                const label = binLabel.label.Truncate(StyleConstants.MAX_CHAR_FOR_HISTOGRAM_LABELS, "...");
+                const textHeight = 14; const textWidth = 30;
+                let xStart = (axis === 0 ? r.xFrom + (r.xTo - r.xFrom) / 2.0 : r.xFrom - 10 - textWidth);
+                let yStart = (axis === 1 ? r.yFrom - textHeight / 2 : r.yFrom);
+
+                if (axis == 0 && vb[axis] instanceof NominalVisualBinRange) {
+                    let space = (r.xTo - r.xFrom) / sc.RenderDimension * this.props.HistoBox.PanelWidth;
+                    xStart += Math.max(textWidth / 2, (1 - textWidth / space) * textWidth / 2) - textHeight / 2;
+                }
+
+                let xPercent = axis == 1 ? `${xStart}px` : `${xStart / sc.RenderDimension * 100}%`
+                let yPercent = axis == 0 ? `${this.props.HistoBox.PanelHeight - sc.BottomOffset - textHeight}px` : `${yStart / sc.RenderDimension * 100}%`
+
+                prims.push(
+                    <div className="histogramLabelPrimitives-placer" key={DashUtils.GenerateGuid()} style={{ transform: `translate(${xPercent}, ${yPercent})` }}>
+                        <div className="histogramLabelPrimitives-gridlabel" style={{ transform: `rotate(${axis == 0 ? sc.LabelAngle : 0}rad)` }}>
+                            {label}
+                        </div>
+                    </div>
+                )
+            }
+            return prims;
+        }, [] as JSX.Element[]);
+    }
+
+    render() {
+        let xaxislines = this.xaxislines;
+        let yaxislines = this.yaxislines;
+        return <div className="histogramLabelPrimitives-container">
+            {xaxislines}
+            {yaxislines}
+        </div>
+    }
+
+}
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2


From 79f9bc805f281a13fe59162f2e25dd1fdcefaae0 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Fri, 29 Mar 2019 20:13:06 -0400
Subject: code cleanup

---
 src/client/northstar/dash-fields/HistogramField.ts |  24 +-
 .../dash-nodes/HistogramBinPrimitiveCollection.ts  | 238 ++++++++++++++++++++
 src/client/northstar/dash-nodes/HistogramBox.tsx   |  21 +-
 .../dash-nodes/HistogramBoxPrimitives.scss         |   4 +
 .../dash-nodes/HistogramBoxPrimitives.tsx          | 246 +--------------------
 .../dash-nodes/HistogramLabelPrimitives.tsx        |   3 +-
 .../northstar/operations/HistogramOperation.ts     |  73 +++---
 7 files changed, 301 insertions(+), 308 deletions(-)
 create mode 100644 src/client/northstar/dash-nodes/HistogramBinPrimitiveCollection.ts

(limited to 'src/client/northstar/dash-nodes/HistogramLabelPrimitives.tsx')

diff --git a/src/client/northstar/dash-fields/HistogramField.ts b/src/client/northstar/dash-fields/HistogramField.ts
index 1929f8dcd..ae83ea5ba 100644
--- a/src/client/northstar/dash-fields/HistogramField.ts
+++ b/src/client/northstar/dash-fields/HistogramField.ts
@@ -15,9 +15,17 @@ export class HistogramField extends BasicField<HistogramOperation> {
         super(data ? data : HistogramOperation.Empty, save, id);
     }
 
+    omitKeys(obj: any, keys: any) {
+        var dup: any = {};
+        for (var key in obj) {
+            if (keys.indexOf(key) == -1) {
+                dup[key] = obj[key];
+            }
+        }
+        return dup;
+    }
     toString(): string {
-        let omitted = this.omitKeys(this.Data, ['Links', 'BrushLinks']);
-        return JSON.stringify(omitted);
+        return JSON.stringify(this.omitKeys(this.Data, ['Links', 'BrushLinks', 'Result']));
     }
 
     Copy(): Field {
@@ -28,22 +36,12 @@ export class HistogramField extends BasicField<HistogramOperation> {
         return `new HistogramField("${this.Data}")`;
     }
 
-    omitKeys(obj: any, keys: any) {
-        var dup: any = {};
-        for (var key in obj) {
-            if (keys.indexOf(key) == -1) {
-                dup[key] = obj[key];
-            }
-        }
-        return dup;
-    }
 
     ToJson(): { type: Types, data: string, _id: string } {
-        let omitted = this.omitKeys(this.Data, ['Links', 'BrushLinks']);
         return {
             type: Types.HistogramOp,
 
-            data: JSON.stringify(omitted),
+            data: this.toString(),
             _id: this.Id
         }
     }
diff --git a/src/client/northstar/dash-nodes/HistogramBinPrimitiveCollection.ts b/src/client/northstar/dash-nodes/HistogramBinPrimitiveCollection.ts
new file mode 100644
index 000000000..43e768c62
--- /dev/null
+++ b/src/client/northstar/dash-nodes/HistogramBinPrimitiveCollection.ts
@@ -0,0 +1,238 @@
+import React = require("react")
+import { AttributeTransformationModel } from "../../northstar/core/attribute/AttributeTransformationModel";
+import { ChartType } from '../../northstar/model/binRanges/VisualBinRange';
+import { AggregateFunction, Bin, Brush, DoubleValueAggregateResult, HistogramResult, MarginAggregateParameters, MarginAggregateResult } from "../../northstar/model/idea/idea";
+import { ModelHelpers } from "../../northstar/model/ModelHelpers";
+import { LABColor } from '../../northstar/utils/LABcolor';
+import { PIXIRectangle } from "../../northstar/utils/MathUtil";
+import { StyleConstants } from "../../northstar/utils/StyleContants";
+import { HistogramBox } from "./HistogramBox";
+import "./HistogramBoxPrimitives.scss";
+
+export class HistogramBinPrimitive {
+    constructor(init?: Partial<HistogramBinPrimitive>) {
+        Object.assign(this, init);
+    }
+    public DataValue: number = 0;
+    public Rect: PIXIRectangle = PIXIRectangle.EMPTY;
+    public MarginRect: PIXIRectangle = PIXIRectangle.EMPTY;
+    public MarginPercentage: number = 0;
+    public Color: number = StyleConstants.WARNING_COLOR;
+    public Opacity: number = 1;
+    public BrushIndex: number = 0;
+    public BarAxis: number = -1;
+}
+
+export class HistogramBinPrimitiveCollection {
+    private static TOLERANCE: number = 0.0001;
+
+    private _histoBox: HistogramBox;
+    private get histoOp() { return this._histoBox.HistoOp; }
+    private get histoResult() { return this.histoOp.Result as HistogramResult; }
+    private get sizeConverter() { return this._histoBox.SizeConverter!; }
+    public BinPrimitives: Array<HistogramBinPrimitive> = new Array<HistogramBinPrimitive>();
+    public HitGeom: PIXIRectangle = PIXIRectangle.EMPTY;
+
+    constructor(bin: Bin, histoBox: HistogramBox) {
+        this._histoBox = histoBox;
+        let brushing = this.setupBrushing(bin, this.histoOp.Normalization); // X= 0, Y = 1, V = 2
+
+        brushing.orderedBrushes.reduce((brushFactorSum, brush) => {
+            switch (histoBox.ChartType) {
+                case ChartType.VerticalBar: return this.createVerticalBarChartBinPrimitives(bin, brush, brushing.maxAxis, this.histoOp.Normalization);
+                case ChartType.HorizontalBar: return this.createHorizontalBarChartBinPrimitives(bin, brush, brushing.maxAxis, this.histoOp.Normalization);
+                case ChartType.SinglePoint: return this.createSinglePointChartBinPrimitives(bin, brush);
+                case ChartType.HeatMap: return this.createHeatmapBinPrimitives(bin, brush, brushFactorSum);
+            }
+        }, 0);
+
+        // adjust brush rects (stacking or not)
+        var allBrushIndex = ModelHelpers.AllBrushIndex(this.histoResult);
+        var filteredBinPrims = this.BinPrimitives.filter(b => b.BrushIndex != allBrushIndex && b.DataValue != 0.0);
+        filteredBinPrims.reduce((sum, fbp) => {
+            if (histoBox.ChartType == ChartType.VerticalBar) {
+                if (this.histoOp.Y.AggregateFunction == AggregateFunction.Count) {
+                    fbp.Rect = new PIXIRectangle(fbp.Rect.x, fbp.Rect.y - sum, fbp.Rect.width, fbp.Rect.height);
+                    fbp.MarginRect = new PIXIRectangle(fbp.MarginRect.x, fbp.MarginRect.y - sum, fbp.MarginRect.width, fbp.MarginRect.height);
+                    return sum + fbp.Rect.height;
+                }
+                if (this.histoOp.Y.AggregateFunction == AggregateFunction.Avg) {
+                    var w = fbp.Rect.width / 2.0;
+                    fbp.Rect = new PIXIRectangle(fbp.Rect.x + sum, fbp.Rect.y, fbp.Rect.width / filteredBinPrims.length, fbp.Rect.height);
+                    fbp.MarginRect = new PIXIRectangle(fbp.MarginRect.x - w + sum + (fbp.Rect.width / 2.0), fbp.MarginRect.y, fbp.MarginRect.width, fbp.MarginRect.height);
+                    return sum + fbp.Rect.width;
+                }
+            }
+            else if (histoBox.ChartType == ChartType.HorizontalBar) {
+                if (this.histoOp.X.AggregateFunction == AggregateFunction.Count) {
+                    fbp.Rect = new PIXIRectangle(fbp.Rect.x + sum, fbp.Rect.y, fbp.Rect.width, fbp.Rect.height);
+                    fbp.MarginRect = new PIXIRectangle(fbp.MarginRect.x + sum, fbp.MarginRect.y, fbp.MarginRect.width, fbp.MarginRect.height);
+                    return sum + fbp.Rect.width;
+                }
+                if (this.histoOp.X.AggregateFunction == AggregateFunction.Avg) {
+                    var h = fbp.Rect.height / 2.0;
+                    fbp.Rect = new PIXIRectangle(fbp.Rect.x, fbp.Rect.y + sum, fbp.Rect.width, fbp.Rect.height / filteredBinPrims.length);
+                    fbp.MarginRect = new PIXIRectangle(fbp.MarginRect.x, fbp.MarginRect.y - h + sum + (fbp.Rect.height / 2.0), fbp.MarginRect.width, fbp.MarginRect.height);
+                    return sum + fbp.Rect.height;
+                }
+            }
+            return 0;
+        }, 0);
+        this.BinPrimitives = this.BinPrimitives.reverse();
+        var f = this.BinPrimitives.filter(b => b.BrushIndex == allBrushIndex);
+        this.HitGeom = f.length > 0 ? f[0].Rect : PIXIRectangle.EMPTY;
+    }
+
+    private setupBrushing(bin: Bin, normalization: number) {
+        var overlapBrushIndex = ModelHelpers.OverlapBrushIndex(this.histoResult);
+        var orderedBrushes = [this.histoResult.brushes![0], this.histoResult.brushes![overlapBrushIndex]];
+        this.histoResult.brushes!.map(brush => brush.brushIndex != 0 && brush.brushIndex != overlapBrushIndex && orderedBrushes.push(brush));
+        return {
+            orderedBrushes,
+            maxAxis: orderedBrushes.reduce((prev, Brush) => {
+                let aggResult = this.getBinValue(normalization, bin, Brush.brushIndex!);
+                return aggResult != undefined && aggResult > prev ? aggResult : prev;
+            }, Number.MIN_VALUE)
+        };
+    }
+
+    private createHeatmapBinPrimitives(bin: Bin, brush: Brush, brushFactorSum: number): number {
+
+        let unNormalizedValue = this.getBinValue(2, bin, brush.brushIndex!);
+        if (unNormalizedValue == undefined)
+            return brushFactorSum;
+
+        var normalizedValue = (unNormalizedValue - this._histoBox.ValueRange[0]) / (Math.abs((this._histoBox.ValueRange[1] - this._histoBox.ValueRange[0])) < HistogramBinPrimitiveCollection.TOLERANCE ?
+            unNormalizedValue : this._histoBox.ValueRange[1] - this._histoBox.ValueRange[0]);
+
+        let allUnNormalizedValue = this.getBinValue(2, bin, ModelHelpers.AllBrushIndex(this.histoResult))
+
+        // bcz: are these calls needed?  
+        let [xFrom, xTo] = this.sizeConverter.DataToScreenXAxisRange(this._histoBox.VisualBinRanges, 0, bin);
+        let [yFrom, yTo] = this.sizeConverter.DataToScreenYAxisRange(this._histoBox.VisualBinRanges, 1, bin);
+
+        var returnBrushFactorSum = brushFactorSum;
+        if (allUnNormalizedValue != undefined) {
+            var brushFactor = (unNormalizedValue / allUnNormalizedValue);
+            returnBrushFactorSum += brushFactor;
+            returnBrushFactorSum = Math.min(returnBrushFactorSum, 1.0);
+
+            var tempRect = new PIXIRectangle(xFrom, yTo, xTo - xFrom, yFrom - yTo);
+            var ratio = (tempRect.width / tempRect.height);
+            var newHeight = Math.sqrt((1.0 / ratio) * ((tempRect.width * tempRect.height) * returnBrushFactorSum));
+            var newWidth = newHeight * ratio;
+
+            xFrom = (tempRect.x + (tempRect.width - newWidth) / 2.0);
+            yTo = (tempRect.y + (tempRect.height - newHeight) / 2.0);
+            xTo = (xFrom + newWidth);
+            yFrom = (yTo + newHeight);
+        }
+        var alpha = 0.0;
+        var color = this.baseColorFromBrush(brush);
+        var lerpColor = LABColor.Lerp(
+            LABColor.FromColor(StyleConstants.MIN_VALUE_COLOR),
+            LABColor.FromColor(color),
+            (alpha + Math.pow(normalizedValue, 1.0 / 3.0) * (1.0 - alpha)));
+        var dataColor = LABColor.ToColor(lerpColor);
+
+        this.createBinPrimitive(-1, brush, PIXIRectangle.EMPTY, 0, xFrom, xTo, yFrom, yTo, dataColor, 1, unNormalizedValue);
+        return returnBrushFactorSum;
+    }
+
+    private createSinglePointChartBinPrimitives(bin: Bin, brush: Brush): number {
+        let unNormalizedValue = this.getBinValue(2, bin, brush.brushIndex!);
+        if (unNormalizedValue != undefined) {
+            let [xFrom, xTo] = this.sizeConverter.DataToScreenPointRange(0, bin, ModelHelpers.CreateAggregateKey(this.histoOp.Schema!.distinctAttributeParameters, this.histoOp.X, this.histoResult, brush.brushIndex!));
+            let [yFrom, yTo] = this.sizeConverter.DataToScreenPointRange(1, bin, ModelHelpers.CreateAggregateKey(this.histoOp.Schema!.distinctAttributeParameters, this.histoOp.Y, this.histoResult, brush.brushIndex!));
+
+            if (xFrom != undefined && yFrom != undefined && xTo != undefined && yTo != undefined)
+                this.createBinPrimitive(-1, brush, PIXIRectangle.EMPTY, 0, xFrom, xTo, yFrom, yTo, this.baseColorFromBrush(brush), 1, unNormalizedValue);
+        }
+        return 0;
+    }
+
+    private createVerticalBarChartBinPrimitives(bin: Bin, brush: Brush, binBrushMaxAxis: number, normalization: number): number {
+        let dataValue = this.getBinValue(1, bin, brush.brushIndex!);
+        if (dataValue != undefined) {
+            let [yFrom, yValue, yTo] = this.sizeConverter.DataToScreenNormalizedRange(dataValue, normalization, 1, binBrushMaxAxis);
+            let [xFrom, xTo] = this.sizeConverter.DataToScreenXAxisRange(this._histoBox.VisualBinRanges, 0, bin);
+
+            var yMarginAbsolute = this.getMargin(bin, brush, this.histoOp.Y);
+            var marginRect = new PIXIRectangle(xFrom + (xTo - xFrom) / 2.0 - 1,
+                this.sizeConverter.DataToScreenY(yValue + yMarginAbsolute), 2,
+                this.sizeConverter.DataToScreenY(yValue - yMarginAbsolute) - this.sizeConverter.DataToScreenY(yValue + yMarginAbsolute));
+
+            this.createBinPrimitive(1, brush, marginRect, 0, xFrom, xTo, yFrom, yTo,
+                this.baseColorFromBrush(brush), normalization != 0 ? 1 : 0.6 * binBrushMaxAxis / this.sizeConverter.DataRanges[1] + 0.4, dataValue);
+        }
+        return 0;
+    }
+
+    private createHorizontalBarChartBinPrimitives(bin: Bin, brush: Brush, binBrushMaxAxis: number, normalization: number): number {
+        let dataValue = this.getBinValue(0, bin, brush.brushIndex!);
+        if (dataValue != undefined) {
+            let [xFrom, xValue, xTo] = this.sizeConverter.DataToScreenNormalizedRange(dataValue, normalization, 0, binBrushMaxAxis);
+            let [yFrom, yTo] = this.sizeConverter.DataToScreenYAxisRange(this._histoBox.VisualBinRanges, 1, bin);
+
+            var xMarginAbsolute = this.sizeConverter.IsSmall ? 0 : this.getMargin(bin, brush, this.histoOp.X);
+            var marginRect = new PIXIRectangle(this.sizeConverter.DataToScreenX(xValue - xMarginAbsolute),
+                yTo + (yFrom - yTo) / 2.0 - 1,
+                this.sizeConverter.DataToScreenX(xValue + xMarginAbsolute) - this.sizeConverter.DataToScreenX(xValue - xMarginAbsolute),
+                2.0);
+
+            this.createBinPrimitive(0, brush, marginRect, 0, xFrom, xTo, yFrom, yTo,
+                this.baseColorFromBrush(brush), normalization != 1 ? 1 : 0.6 * binBrushMaxAxis / this.sizeConverter.DataRanges[0] + 0.4, dataValue);
+        }
+        return 0;
+    }
+
+    public getBinValue(axis: number, bin: Bin, brushIndex: number) {
+        var aggregateKey = ModelHelpers.CreateAggregateKey(this.histoOp.Schema!.distinctAttributeParameters, axis == 0 ? this.histoOp.X : axis == 1 ? this.histoOp.Y : this.histoOp.V, this.histoResult, brushIndex);
+        let dataValue = ModelHelpers.GetAggregateResult(bin, aggregateKey) as DoubleValueAggregateResult;
+        return dataValue != null && dataValue.hasResult ? dataValue.result : undefined;
+    }
+
+    private getMargin(bin: Bin, brush: Brush, axis: AttributeTransformationModel) {
+        var marginParams = new MarginAggregateParameters();
+        marginParams.aggregateFunction = axis.AggregateFunction;
+        var marginAggregateKey = ModelHelpers.CreateAggregateKey(this.histoOp.Schema!.distinctAttributeParameters, axis, this.histoResult, brush.brushIndex!, marginParams);
+        var marginResult = ModelHelpers.GetAggregateResult(bin, marginAggregateKey) as MarginAggregateResult;
+        return !marginResult ? 0 : marginResult.absolutMargin!;
+    }
+
+    private createBinPrimitive(barAxis: number, brush: Brush, marginRect: PIXIRectangle,
+        marginPercentage: number, xFrom: number, xTo: number, yFrom: number, yTo: number, color: number, opacity: number, dataValue: number) {
+        var binPrimitive = new HistogramBinPrimitive(
+            {
+                Rect: new PIXIRectangle(xFrom, yTo, xTo - xFrom, yFrom - yTo),
+                MarginRect: marginRect,
+                MarginPercentage: marginPercentage,
+                BrushIndex: brush.brushIndex,
+                Color: color,
+                Opacity: opacity,
+                DataValue: dataValue,
+                BarAxis: barAxis
+            });
+        this.BinPrimitives.push(binPrimitive);
+    }
+
+    private baseColorFromBrush(brush: Brush): number {
+        let bc = StyleConstants.BRUSH_COLORS;
+        if (brush.brushIndex == ModelHelpers.RestBrushIndex(this.histoResult)) {
+            return StyleConstants.HIGHLIGHT_COLOR;
+        }
+        else if (brush.brushIndex == ModelHelpers.OverlapBrushIndex(this.histoResult)) {
+            return StyleConstants.OVERLAP_COLOR;
+        }
+        else if (brush.brushIndex == ModelHelpers.AllBrushIndex(this.histoResult)) {
+            return 0x00ff00;
+        }
+        else if (bc.length > 0) {
+            return bc[brush.brushIndex! % bc.length];
+        }
+        // else if (this.histoOp.BrushColors.length > 0) {
+        //     return this.histoOp.BrushColors[brush.brushIndex! % this.histoOp.BrushColors.length];
+        // }
+        return StyleConstants.HIGHLIGHT_COLOR;
+    }
+}
\ No newline at end of file
diff --git a/src/client/northstar/dash-nodes/HistogramBox.tsx b/src/client/northstar/dash-nodes/HistogramBox.tsx
index 9976ff6ad..6bf2697fc 100644
--- a/src/client/northstar/dash-nodes/HistogramBox.tsx
+++ b/src/client/northstar/dash-nodes/HistogramBox.tsx
@@ -22,9 +22,6 @@ import { HistogramBoxPrimitives } from './HistogramBoxPrimitives';
 import { HistogramLabelPrimitives } from "./HistogramLabelPrimitives";
 import { StyleConstants } from "../utils/StyleContants";
 
-export interface HistogramPrimitivesProps {
-    HistoBox: HistogramBox;
-}
 
 @observer
 export class HistogramBox extends React.Component<FieldViewProps> {
@@ -77,6 +74,15 @@ export class HistogramBox extends React.Component<FieldViewProps> {
         }
     }
 
+    @action
+    xLabelPointerDown = (e: React.PointerEvent) => {
+        this.HistoOp.X = new AttributeTransformationModel(this.HistoOp.X.AttributeModel, this.HistoOp.X.AggregateFunction == AggregateFunction.None ? AggregateFunction.Count : AggregateFunction.None);
+    }
+    @action
+    yLabelPointerDown = (e: React.PointerEvent) => {
+        this.HistoOp.Y = new AttributeTransformationModel(this.HistoOp.Y.AttributeModel, this.HistoOp.Y.AggregateFunction == AggregateFunction.None ? AggregateFunction.Count : AggregateFunction.None);
+    }
+
     componentDidMount() {
         if (this._dropXRef.current) {
             this._dropXDisposer = DragManager.MakeDropTarget(this._dropXRef.current, { handlers: { drop: this.dropX.bind(this) } });
@@ -102,15 +108,6 @@ export class HistogramBox extends React.Component<FieldViewProps> {
             });
     }
 
-    @action
-    xLabelPointerDown = (e: React.PointerEvent) => {
-        this.HistoOp.X = new AttributeTransformationModel(this.HistoOp.X.AttributeModel, this.HistoOp.X.AggregateFunction == AggregateFunction.None ? AggregateFunction.Count : AggregateFunction.None);
-    }
-    @action
-    yLabelPointerDown = (e: React.PointerEvent) => {
-        this.HistoOp.Y = new AttributeTransformationModel(this.HistoOp.Y.AttributeModel, this.HistoOp.Y.AggregateFunction == AggregateFunction.None ? AggregateFunction.Count : AggregateFunction.None);
-    }
-
     componentWillUnmount() {
         if (this._dropXDisposer)
             this._dropXDisposer();
diff --git a/src/client/northstar/dash-nodes/HistogramBoxPrimitives.scss b/src/client/northstar/dash-nodes/HistogramBoxPrimitives.scss
index 9d42219cc..ce9edd65e 100644
--- a/src/client/northstar/dash-nodes/HistogramBoxPrimitives.scss
+++ b/src/client/northstar/dash-nodes/HistogramBoxPrimitives.scss
@@ -1,3 +1,7 @@
+.histogramboxprimitives-container {
+    width: 100%;
+    height: 100%;
+}
 .histogramboxprimitives-border {
     border: 3px;
     border-style: solid;
diff --git a/src/client/northstar/dash-nodes/HistogramBoxPrimitives.tsx b/src/client/northstar/dash-nodes/HistogramBoxPrimitives.tsx
index c97acb064..e9adb3ce5 100644
--- a/src/client/northstar/dash-nodes/HistogramBoxPrimitives.tsx
+++ b/src/client/northstar/dash-nodes/HistogramBoxPrimitives.tsx
@@ -1,27 +1,24 @@
 import React = require("react")
-import { computed, observable, runInAction, reaction, untracked, trace } from "mobx";
+import { computed, observable, reaction, runInAction, trace } from "mobx";
 import { observer } from "mobx-react";
 import { Utils as DashUtils } from '../../../Utils';
-import { AttributeTransformationModel } from "../../northstar/core/attribute/AttributeTransformationModel";
 import { FilterModel } from "../../northstar/core/filter/FilterModel";
-import { ChartType } from '../../northstar/model/binRanges/VisualBinRange';
-import { AggregateFunction, Bin, Brush, HistogramResult, MarginAggregateParameters, MarginAggregateResult } from "../../northstar/model/idea/idea";
 import { ModelHelpers } from "../../northstar/model/ModelHelpers";
 import { ArrayUtil } from "../../northstar/utils/ArrayUtil";
 import { LABColor } from '../../northstar/utils/LABcolor';
 import { PIXIRectangle } from "../../northstar/utils/MathUtil";
 import { StyleConstants } from "../../northstar/utils/StyleContants";
-import { HistogramBox, HistogramPrimitivesProps } from "./HistogramBox";
+import { HistogramBinPrimitiveCollection, HistogramBinPrimitive } from "./HistogramBinPrimitiveCollection";
+import { HistogramBox } from "./HistogramBox";
 import "./HistogramBoxPrimitives.scss";
 
-
+export interface HistogramPrimitivesProps {
+    HistoBox: HistogramBox;
+}
 @observer
 export class HistogramBoxPrimitives extends React.Component<HistogramPrimitivesProps> {
     private get histoOp() { return this.props.HistoBox.HistoOp; }
     private get renderDimension() { return this.props.HistoBox.SizeConverter.RenderDimension; }
-    componentDidMount() {
-        reaction(() => this.props.HistoBox.HistoOp.FilterString, () => this._selectedPrims.length = this.histoOp.FilterModels.length = 0);
-    }
     @observable _selectedPrims: HistogramBinPrimitive[] = [];
     @computed get xaxislines() { return this.renderGridLinesAndLabels(0); }
     @computed get yaxislines() { return this.renderGridLinesAndLabels(1); }
@@ -42,6 +39,10 @@ export class HistogramBoxPrimitives extends React.Component<HistogramPrimitivesP
         }, [] as JSX.Element[]);
     }
 
+    componentDidMount() {
+        reaction(() => this.props.HistoBox.HistoOp.FilterString, () => this._selectedPrims.length = this.histoOp.FilterModels.length = 0);
+    }
+
     private getSelectionToggle(binPrimitives: HistogramBinPrimitive[], allBrushIndex: number, filterModel: FilterModel) {
         let allBrushPrim = ArrayUtil.FirstOrDefault(binPrimitives, bp => bp.BrushIndex == allBrushIndex);
         return !allBrushPrim ? () => { } : () => runInAction(() => {
@@ -90,7 +91,6 @@ export class HistogramBoxPrimitives extends React.Component<HistogramPrimitivesP
         let line = (<div className="histogramboxprimitives-line" style={{ width: trans2Xpercent, height: trans2Ypercent, }} />);
         return this.drawEntity(xFrom, yFrom, line);
     }
-
     drawRect(r: PIXIRectangle, barAxis: number, color: number | undefined, classExt: string, tapHandler: () => void = () => { }) {
         if (r.height < 0) {
             r.y += r.height;
@@ -114,235 +114,11 @@ export class HistogramBoxPrimitives extends React.Component<HistogramPrimitivesP
         return this.drawEntity(r.x, r.y, rect);
     }
     render() {
-        return <div className="histogramboxprimitives-container" style={{
-            width: "100%",
-            height: "100%",
-        }}>
+        return <div className="histogramboxprimitives-container">
             {this.xaxislines}
             {this.yaxislines}
             {this.binPrimitives}
             {this.selectedPrimitives}
         </div>
     }
-}
-
-class HistogramBinPrimitive {
-    constructor(init?: Partial<HistogramBinPrimitive>) {
-        Object.assign(this, init);
-    }
-    public DataValue: number = 0;
-    public Rect: PIXIRectangle = PIXIRectangle.EMPTY;
-    public MarginRect: PIXIRectangle = PIXIRectangle.EMPTY;
-    public MarginPercentage: number = 0;
-    public Color: number = StyleConstants.WARNING_COLOR;
-    public Opacity: number = 1;
-    public BrushIndex: number = 0;
-    public BarAxis: number = -1;
-}
-
-export class HistogramBinPrimitiveCollection {
-    private static TOLERANCE: number = 0.0001;
-
-    private _histoBox: HistogramBox;
-    private get histoOp() { return this._histoBox.HistoOp; }
-    private get histoResult() { return this.histoOp.Result as HistogramResult; }
-    private get sizeConverter() { return this._histoBox.SizeConverter!; }
-    public BinPrimitives: Array<HistogramBinPrimitive> = new Array<HistogramBinPrimitive>();
-    public HitGeom: PIXIRectangle = PIXIRectangle.EMPTY;
-
-    constructor(bin: Bin, histoBox: HistogramBox) {
-        this._histoBox = histoBox;
-        let brushing = this.setupBrushing(bin, this.histoOp.Normalization); // X= 0, Y = 1, V = 2
-
-        brushing.orderedBrushes.reduce((brushFactorSum, brush) => {
-            switch (histoBox.ChartType) {
-                case ChartType.VerticalBar: return this.createVerticalBarChartBinPrimitives(bin, brush, brushing.maxAxis, this.histoOp.Normalization);
-                case ChartType.HorizontalBar: return this.createHorizontalBarChartBinPrimitives(bin, brush, brushing.maxAxis, this.histoOp.Normalization);
-                case ChartType.SinglePoint: return this.createSinglePointChartBinPrimitives(bin, brush);
-                case ChartType.HeatMap: return this.createHeatmapBinPrimitives(bin, brush, brushFactorSum);
-            }
-        }, 0);
-
-        // adjust brush rects (stacking or not)
-        var allBrushIndex = ModelHelpers.AllBrushIndex(this.histoResult);
-        var filteredBinPrims = this.BinPrimitives.filter(b => b.BrushIndex != allBrushIndex && b.DataValue != 0.0);
-        filteredBinPrims.reduce((sum, fbp) => {
-            if (histoBox.ChartType == ChartType.VerticalBar) {
-                if (this.histoOp.Y.AggregateFunction == AggregateFunction.Count) {
-                    fbp.Rect = new PIXIRectangle(fbp.Rect.x, fbp.Rect.y - sum, fbp.Rect.width, fbp.Rect.height);
-                    fbp.MarginRect = new PIXIRectangle(fbp.MarginRect.x, fbp.MarginRect.y - sum, fbp.MarginRect.width, fbp.MarginRect.height);
-                    return sum + fbp.Rect.height;
-                }
-                if (this.histoOp.Y.AggregateFunction == AggregateFunction.Avg) {
-                    var w = fbp.Rect.width / 2.0;
-                    fbp.Rect = new PIXIRectangle(fbp.Rect.x + sum, fbp.Rect.y, fbp.Rect.width / filteredBinPrims.length, fbp.Rect.height);
-                    fbp.MarginRect = new PIXIRectangle(fbp.MarginRect.x - w + sum + (fbp.Rect.width / 2.0), fbp.MarginRect.y, fbp.MarginRect.width, fbp.MarginRect.height);
-                    return sum + fbp.Rect.width;
-                }
-            }
-            else if (histoBox.ChartType == ChartType.HorizontalBar) {
-                if (this.histoOp.X.AggregateFunction == AggregateFunction.Count) {
-                    fbp.Rect = new PIXIRectangle(fbp.Rect.x + sum, fbp.Rect.y, fbp.Rect.width, fbp.Rect.height);
-                    fbp.MarginRect = new PIXIRectangle(fbp.MarginRect.x + sum, fbp.MarginRect.y, fbp.MarginRect.width, fbp.MarginRect.height);
-                    return sum + fbp.Rect.width;
-                }
-                if (this.histoOp.X.AggregateFunction == AggregateFunction.Avg) {
-                    var h = fbp.Rect.height / 2.0;
-                    fbp.Rect = new PIXIRectangle(fbp.Rect.x, fbp.Rect.y + sum, fbp.Rect.width, fbp.Rect.height / filteredBinPrims.length);
-                    fbp.MarginRect = new PIXIRectangle(fbp.MarginRect.x, fbp.MarginRect.y - h + sum + (fbp.Rect.height / 2.0), fbp.MarginRect.width, fbp.MarginRect.height);
-                    return sum + fbp.Rect.height;
-                }
-            }
-            return 0;
-        }, 0);
-        this.BinPrimitives = this.BinPrimitives.reverse();
-        var f = this.BinPrimitives.filter(b => b.BrushIndex == allBrushIndex);
-        this.HitGeom = f.length > 0 ? f[0].Rect : PIXIRectangle.EMPTY;
-    }
-    private setupBrushing(bin: Bin, normalization: number) {
-        var overlapBrushIndex = ModelHelpers.OverlapBrushIndex(this.histoResult);
-        var orderedBrushes = [this.histoResult.brushes![0], this.histoResult.brushes![overlapBrushIndex]];
-        this.histoResult.brushes!.map(brush => brush.brushIndex != 0 && brush.brushIndex != overlapBrushIndex && orderedBrushes.push(brush));
-        return {
-            orderedBrushes,
-            maxAxis: orderedBrushes.reduce((prev, Brush) => {
-                let aggResult = this.histoOp.getValue(normalization, bin, this.histoResult, Brush.brushIndex!);
-                return aggResult != undefined && aggResult > prev ? aggResult : prev;
-            }, Number.MIN_VALUE)
-        };
-    }
-    private createHeatmapBinPrimitives(bin: Bin, brush: Brush, brushFactorSum: number): number {
-
-        let unNormalizedValue = this.histoOp.getValue(2, bin, this.histoResult, brush.brushIndex!);
-        if (unNormalizedValue == undefined)
-            return brushFactorSum;
-
-        var normalizedValue = (unNormalizedValue - this._histoBox.ValueRange[0]) / (Math.abs((this._histoBox.ValueRange[1] - this._histoBox.ValueRange[0])) < HistogramBinPrimitiveCollection.TOLERANCE ?
-            unNormalizedValue : this._histoBox.ValueRange[1] - this._histoBox.ValueRange[0]);
-
-        let allUnNormalizedValue = this.histoOp.getValue(2, bin, this.histoResult, ModelHelpers.AllBrushIndex(this.histoResult))
-
-        // bcz: are these calls needed?  
-        let [xFrom, xTo] = this.sizeConverter.DataToScreenXAxisRange(this._histoBox.VisualBinRanges, 0, bin);
-        let [yFrom, yTo] = this.sizeConverter.DataToScreenYAxisRange(this._histoBox.VisualBinRanges, 1, bin);
-
-        var returnBrushFactorSum = brushFactorSum;
-        if (allUnNormalizedValue != undefined) {
-            var brushFactor = (unNormalizedValue / allUnNormalizedValue);
-            returnBrushFactorSum += brushFactor;
-            returnBrushFactorSum = Math.min(returnBrushFactorSum, 1.0);
-
-            var tempRect = new PIXIRectangle(xFrom, yTo, xTo - xFrom, yFrom - yTo);
-            var ratio = (tempRect.width / tempRect.height);
-            var newHeight = Math.sqrt((1.0 / ratio) * ((tempRect.width * tempRect.height) * returnBrushFactorSum));
-            var newWidth = newHeight * ratio;
-
-            xFrom = (tempRect.x + (tempRect.width - newWidth) / 2.0);
-            yTo = (tempRect.y + (tempRect.height - newHeight) / 2.0);
-            xTo = (xFrom + newWidth);
-            yFrom = (yTo + newHeight);
-        }
-        var alpha = 0.0;
-        var color = this.baseColorFromBrush(brush);
-        var lerpColor = LABColor.Lerp(
-            LABColor.FromColor(StyleConstants.MIN_VALUE_COLOR),
-            LABColor.FromColor(color),
-            (alpha + Math.pow(normalizedValue, 1.0 / 3.0) * (1.0 - alpha)));
-        var dataColor = LABColor.ToColor(lerpColor);
-
-        this.createBinPrimitive(-1, brush, PIXIRectangle.EMPTY, 0, xFrom, xTo, yFrom, yTo, dataColor, 1, unNormalizedValue);
-        return returnBrushFactorSum;
-    }
-
-    private createSinglePointChartBinPrimitives(bin: Bin, brush: Brush): number {
-        let unNormalizedValue = this._histoBox.HistoOp.getValue(2, bin, this.histoResult, brush.brushIndex!);
-        if (unNormalizedValue != undefined) {
-            let [xFrom, xTo] = this.sizeConverter.DataToScreenPointRange(0, bin, ModelHelpers.CreateAggregateKey(this.histoOp.Schema!.distinctAttributeParameters, this.histoOp.X, this.histoResult, brush.brushIndex!));
-            let [yFrom, yTo] = this.sizeConverter.DataToScreenPointRange(1, bin, ModelHelpers.CreateAggregateKey(this.histoOp.Schema!.distinctAttributeParameters, this.histoOp.Y, this.histoResult, brush.brushIndex!));
-
-            if (xFrom != undefined && yFrom != undefined && xTo != undefined && yTo != undefined)
-                this.createBinPrimitive(-1, brush, PIXIRectangle.EMPTY, 0, xFrom, xTo, yFrom, yTo, this.baseColorFromBrush(brush), 1, unNormalizedValue);
-        }
-        return 0;
-    }
-
-    private createVerticalBarChartBinPrimitives(bin: Bin, brush: Brush, binBrushMaxAxis: number, normalization: number): number {
-        let dataValue = this.histoOp.getValue(1, bin, this.histoResult, brush.brushIndex!);
-        if (dataValue != undefined) {
-            let [yFrom, yValue, yTo] = this.sizeConverter.DataToScreenNormalizedRange(dataValue, normalization, 1, binBrushMaxAxis);
-            let [xFrom, xTo] = this.sizeConverter.DataToScreenXAxisRange(this._histoBox.VisualBinRanges, 0, bin);
-
-            var yMarginAbsolute = this.getMargin(bin, brush, this.histoOp.Y);
-            var marginRect = new PIXIRectangle(xFrom + (xTo - xFrom) / 2.0 - 1,
-                this.sizeConverter.DataToScreenY(yValue + yMarginAbsolute), 2,
-                this.sizeConverter.DataToScreenY(yValue - yMarginAbsolute) - this.sizeConverter.DataToScreenY(yValue + yMarginAbsolute));
-
-            this.createBinPrimitive(1, brush, marginRect, 0, xFrom, xTo, yFrom, yTo,
-                this.baseColorFromBrush(brush), normalization != 0 ? 1 : 0.6 * binBrushMaxAxis / this.sizeConverter.DataRanges[1] + 0.4, dataValue);
-        }
-        return 0;
-    }
-
-    private createHorizontalBarChartBinPrimitives(bin: Bin, brush: Brush, binBrushMaxAxis: number, normalization: number): number {
-        let dataValue = this.histoOp.getValue(0, bin, this.histoResult, brush.brushIndex!);
-        if (dataValue != undefined) {
-            let [xFrom, xValue, xTo] = this.sizeConverter.DataToScreenNormalizedRange(dataValue, normalization, 0, binBrushMaxAxis);
-            let [yFrom, yTo] = this.sizeConverter.DataToScreenYAxisRange(this._histoBox.VisualBinRanges, 1, bin);
-
-            var xMarginAbsolute = this.sizeConverter.IsSmall ? 0 : this.getMargin(bin, brush, this.histoOp.X);
-            var marginRect = new PIXIRectangle(this.sizeConverter.DataToScreenX(xValue - xMarginAbsolute),
-                yTo + (yFrom - yTo) / 2.0 - 1,
-                this.sizeConverter.DataToScreenX(xValue + xMarginAbsolute) - this.sizeConverter.DataToScreenX(xValue - xMarginAbsolute),
-                2.0);
-
-            this.createBinPrimitive(0, brush, marginRect, 0, xFrom, xTo, yFrom, yTo,
-                this.baseColorFromBrush(brush), normalization != 1 ? 1 : 0.6 * binBrushMaxAxis / this.sizeConverter.DataRanges[0] + 0.4, dataValue);
-        }
-        return 0;
-    }
-
-
-    private getMargin(bin: Bin, brush: Brush, axis: AttributeTransformationModel) {
-        var marginParams = new MarginAggregateParameters();
-        marginParams.aggregateFunction = axis.AggregateFunction;
-        var marginAggregateKey = ModelHelpers.CreateAggregateKey(this.histoOp.Schema!.distinctAttributeParameters, axis, this.histoResult, brush.brushIndex!, marginParams);
-        var marginResult = ModelHelpers.GetAggregateResult(bin, marginAggregateKey) as MarginAggregateResult;
-        return !marginResult ? 0 : marginResult.absolutMargin!;
-    }
-
-    private createBinPrimitive(barAxis: number, brush: Brush, marginRect: PIXIRectangle,
-        marginPercentage: number, xFrom: number, xTo: number, yFrom: number, yTo: number, color: number, opacity: number, dataValue: number) {
-        var binPrimitive = new HistogramBinPrimitive(
-            {
-                Rect: new PIXIRectangle(xFrom, yTo, xTo - xFrom, yFrom - yTo),
-                MarginRect: marginRect,
-                MarginPercentage: marginPercentage,
-                BrushIndex: brush.brushIndex,
-                Color: color,
-                Opacity: opacity,
-                DataValue: dataValue,
-                BarAxis: barAxis
-            });
-        this.BinPrimitives.push(binPrimitive);
-    }
-
-    private baseColorFromBrush(brush: Brush): number {
-        let bc = StyleConstants.BRUSH_COLORS;
-        if (brush.brushIndex == ModelHelpers.RestBrushIndex(this.histoResult)) {
-            return StyleConstants.HIGHLIGHT_COLOR;
-        }
-        else if (brush.brushIndex == ModelHelpers.OverlapBrushIndex(this.histoResult)) {
-            return StyleConstants.OVERLAP_COLOR;
-        }
-        else if (brush.brushIndex == ModelHelpers.AllBrushIndex(this.histoResult)) {
-            return 0x00ff00;
-        }
-        else if (bc.length > 0) {
-            return bc[brush.brushIndex! % bc.length];
-        }
-        // else if (this.histoOp.BrushColors.length > 0) {
-        //     return this.histoOp.BrushColors[brush.brushIndex! % this.histoOp.BrushColors.length];
-        // }
-        return StyleConstants.HIGHLIGHT_COLOR;
-    }
 }
\ No newline at end of file
diff --git a/src/client/northstar/dash-nodes/HistogramLabelPrimitives.tsx b/src/client/northstar/dash-nodes/HistogramLabelPrimitives.tsx
index 45b23874d..93b237deb 100644
--- a/src/client/northstar/dash-nodes/HistogramLabelPrimitives.tsx
+++ b/src/client/northstar/dash-nodes/HistogramLabelPrimitives.tsx
@@ -5,8 +5,9 @@ import { Utils as DashUtils } from '../../../Utils';
 import { NominalVisualBinRange } from "../model/binRanges/NominalVisualBinRange";
 import "../utils/Extensions";
 import { StyleConstants } from "../utils/StyleContants";
-import { HistogramBox, HistogramPrimitivesProps } from "./HistogramBox";
+import { HistogramBox } from "./HistogramBox";
 import "./HistogramLabelPrimitives.scss";
+import { HistogramPrimitivesProps } from "./HistogramBoxPrimitives";
 
 @observer
 export class HistogramLabelPrimitives extends React.Component<HistogramPrimitivesProps> {
diff --git a/src/client/northstar/operations/HistogramOperation.ts b/src/client/northstar/operations/HistogramOperation.ts
index 48bad73df..4689cb233 100644
--- a/src/client/northstar/operations/HistogramOperation.ts
+++ b/src/client/northstar/operations/HistogramOperation.ts
@@ -1,5 +1,7 @@
 import { action, computed, observable, trace } from "mobx";
 import { Document } from "../../../fields/Document";
+import { FieldWaiting } from "../../../fields/Field";
+import { KeyStore } from "../../../fields/KeyStore";
 import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils";
 import { ColumnAttributeModel } from "../core/attribute/AttributeModel";
 import { AttributeTransformationModel } from "../core/attribute/AttributeTransformationModel";
@@ -7,52 +9,30 @@ import { CalculatedAttributeManager } from "../core/attribute/CalculatedAttribut
 import { FilterModel } from "../core/filter/FilterModel";
 import { FilterOperand } from "../core/filter/FilterOperand";
 import { IBaseFilterConsumer } from "../core/filter/IBaseFilterConsumer";
-import { IBaseFilterProvider, instanceOfIBaseFilterProvider } from "../core/filter/IBaseFilterProvider";
+import { IBaseFilterProvider } from "../core/filter/IBaseFilterProvider";
+import { HistogramField } from "../dash-fields/HistogramField";
 import { SETTINGS_SAMPLE_SIZE, SETTINGS_X_BINS, SETTINGS_Y_BINS } from "../model/binRanges/VisualBinRangeHelper";
-import { AggregateFunction, AggregateParameters, Attribute, AverageAggregateParameters, DataType, HistogramOperationParameters, QuantitativeBinRange, HistogramResult, Brush, DoubleValueAggregateResult, Bin } from "../model/idea/idea";
+import { AggregateFunction, AggregateParameters, Attribute, AverageAggregateParameters, Bin, DataType, DoubleValueAggregateResult, HistogramOperationParameters, HistogramResult, QuantitativeBinRange } from "../model/idea/idea";
 import { ModelHelpers } from "../model/ModelHelpers";
 import { ArrayUtil } from "../utils/ArrayUtil";
 import { BaseOperation } from "./BaseOperation";
-import { KeyStore } from "../../../fields/KeyStore";
-import { HistogramField } from "../dash-fields/HistogramField";
-import { FieldWaiting } from "../../../fields/Field";
-import { StyleConstants } from "../utils/StyleContants";
-
 
 export class HistogramOperation extends BaseOperation implements IBaseFilterConsumer, IBaseFilterProvider {
+    public static Empty = new HistogramOperation("-empty schema-", new AttributeTransformationModel(new ColumnAttributeModel(new Attribute())), new AttributeTransformationModel(new ColumnAttributeModel(new Attribute())), new AttributeTransformationModel(new ColumnAttributeModel(new Attribute())));
     @observable public FilterOperand: FilterOperand = FilterOperand.AND;
     @observable public Links: Document[] = [];
     @observable public BrushLinks: { l: Document, b: Document }[] = [];
     @observable public BrushColors: number[] = [];
-    @observable public Normalization: number = -1;
     @observable public FilterModels: FilterModel[] = [];
+
+    @observable public Normalization: number = -1;
     @observable public X: AttributeTransformationModel;
     @observable public Y: AttributeTransformationModel;
     @observable public V: AttributeTransformationModel;
     @observable public SchemaName: string;
+    @observable public QRange: QuantitativeBinRange | undefined;
     @computed public get Schema() { return CurrentUserUtils.GetNorthstarSchema(this.SchemaName); }
 
-    @action
-    public AddFilterModels(filterModels: FilterModel[]): void {
-        filterModels.filter(f => f !== null).forEach(fm => this.FilterModels.push(fm));
-    }
-    @action
-    public RemoveFilterModels(filterModels: FilterModel[]): void {
-        ArrayUtil.RemoveMany(this.FilterModels, filterModels);
-    }
-
-    public getValue(axis: number, bin: Bin, result: HistogramResult, brushIndex: number) {
-        var aggregateKey = ModelHelpers.CreateAggregateKey(this.Schema!.distinctAttributeParameters, axis == 0 ? this.X : axis == 1 ? this.Y : this.V, result, brushIndex);
-        let dataValue = ModelHelpers.GetAggregateResult(bin, aggregateKey) as DoubleValueAggregateResult;
-        return dataValue != null && dataValue.hasResult ? dataValue.result : undefined;
-    }
-
-    public static Empty = new HistogramOperation("-empty schema-", new AttributeTransformationModel(new ColumnAttributeModel(new Attribute())), new AttributeTransformationModel(new ColumnAttributeModel(new Attribute())), new AttributeTransformationModel(new ColumnAttributeModel(new Attribute())));
-
-    Equals(other: Object): boolean {
-        throw new Error("Method not implemented.");
-    }
-
     constructor(schemaName: string, x: AttributeTransformationModel, y: AttributeTransformationModel, v: AttributeTransformationModel, normalized?: number) {
         super();
         this.X = x;
@@ -62,6 +42,19 @@ export class HistogramOperation extends BaseOperation implements IBaseFilterCons
         this.SchemaName = schemaName;
     }
 
+    Equals(other: Object): boolean {
+        throw new Error("Method not implemented.");
+    }
+
+    @action
+    public AddFilterModels(filterModels: FilterModel[]): void {
+        filterModels.filter(f => f !== null).forEach(fm => this.FilterModels.push(fm));
+    }
+    @action
+    public RemoveFilterModels(filterModels: FilterModel[]): void {
+        ArrayUtil.RemoveMany(this.FilterModels, filterModels);
+    }
+
     @computed
     public get FilterString(): string {
         let filterModels: FilterModel[] = [];
@@ -73,25 +66,16 @@ export class HistogramOperation extends BaseOperation implements IBaseFilterCons
         trace();
         let brushes: string[] = [];
         this.BrushLinks.map(brushLink => {
-            let brusherDoc = brushLink.b;
-            let brushHistogram = brusherDoc.GetT(KeyStore.Data, HistogramField);
+            let brushHistogram = brushLink.b.GetT(KeyStore.Data, HistogramField);
             if (brushHistogram && brushHistogram != FieldWaiting) {
                 let filterModels: FilterModel[] = [];
-                let brush = FilterModel.GetFilterModelsRecursive(brushHistogram!.Data, new Set<IBaseFilterProvider>(), filterModels, false)
-                brushes.push(brush);
+                brushes.push(FilterModel.GetFilterModelsRecursive(brushHistogram.Data, new Set<IBaseFilterProvider>(), filterModels, false));
             }
         });
         return brushes;
     }
 
-
-    @computed.struct
-    public get SelectionString() {
-        let filterModels = new Array<FilterModel>();
-        return FilterModel.GetFilterModelsRecursive(this, new Set<IBaseFilterProvider>(), filterModels, false);
-    }
-
-    GetAggregateParameters(histoX: AttributeTransformationModel, histoY: AttributeTransformationModel, histoValue: AttributeTransformationModel) {
+    private getAggregateParameters(histoX: AttributeTransformationModel, histoY: AttributeTransformationModel, histoValue: AttributeTransformationModel) {
         let allAttributes = new Array<AttributeTransformationModel>(histoX, histoY, histoValue);
         allAttributes = ArrayUtil.Distinct(allAttributes.filter(a => a.AggregateFunction !== AggregateFunction.None));
 
@@ -108,11 +92,9 @@ export class HistogramOperation extends BaseOperation implements IBaseFilterCons
         return [perBinAggregateParameters, globalAggregateParameters];
     }
 
-    public QRange: QuantitativeBinRange | undefined;
-
     public CreateOperationParameters(): HistogramOperationParameters | undefined {
         if (this.X && this.Y && this.V) {
-            let [perBinAggregateParameters, globalAggregateParameters] = this.GetAggregateParameters(this.X, this.Y, this.V);
+            let [perBinAggregateParameters, globalAggregateParameters] = this.getAggregateParameters(this.X, this.Y, this.V);
             return new HistogramOperationParameters({
                 enableBrushComputation: true,
                 adapterName: this.SchemaName,
@@ -131,9 +113,6 @@ export class HistogramOperation extends BaseOperation implements IBaseFilterCons
             });
         }
     }
-    get_random_color(): number {
-        return (Math.floor(Math.random() * 256) << 16) + (Math.floor(Math.random() * 256) << 8) + (Math.floor(Math.random() * 256));
-    }
 
     @action
     public async Update(): Promise<void> {
-- 
cgit v1.2.3-70-g09d2

