diff options
author | bob <bcz@cs.brown.edu> | 2019-03-26 16:06:06 -0400 |
---|---|---|
committer | bob <bcz@cs.brown.edu> | 2019-03-26 16:06:06 -0400 |
commit | e9826e0ac334bac28d173f67b4f0db0800b40680 (patch) | |
tree | 445801d2f3971243045682e13c1cd6bf0ac371a8 | |
parent | b9d23e5adde2da01708cc8501ca375726d232d06 (diff) |
cleaned up a bit. got rid of blinking when histos change.
-rw-r--r-- | src/client/northstar/core/filter/FilterModel.ts | 50 | ||||
-rw-r--r-- | src/client/northstar/operations/BaseOperation.ts | 3 | ||||
-rw-r--r-- | src/client/northstar/operations/HistogramOperation.ts | 1 | ||||
-rw-r--r-- | src/client/views/nodes/DocumentContentsView.tsx | 3 | ||||
-rw-r--r-- | src/client/views/nodes/HistogramBox.tsx | 360 | ||||
-rw-r--r-- | src/client/views/nodes/HistogramBoxPrimitives.tsx | 373 |
6 files changed, 399 insertions, 391 deletions
diff --git a/src/client/northstar/core/filter/FilterModel.ts b/src/client/northstar/core/filter/FilterModel.ts index a9c79d245..bc7938947 100644 --- a/src/client/northstar/core/filter/FilterModel.ts +++ b/src/client/northstar/core/filter/FilterModel.ts @@ -1,11 +1,9 @@ import { ValueComparison } from "./ValueComparision"; import { Utils } from "../../utils/Utils"; -import { IBaseFilterProvider, instanceOfIBaseFilterProvider } from "./IBaseFilterProvider"; -import { BaseOperation } from "../../operations/BaseOperation"; +import { IBaseFilterProvider } from "./IBaseFilterProvider"; import { FilterOperand } from "./FilterOperand"; import { HistogramField } from "../../../../fields/HistogramField"; import { KeyStore } from "../../../../fields/KeyStore"; -import { filter } from "bluebird"; import { FieldWaiting } from "../../../../fields/Field"; import { Document } from "../../../../fields/Document"; @@ -35,8 +33,7 @@ export class FilterModel { } public ToPythonString(): string { - let ret = "(" + this.ValueComparisons.map(vc => vc.ToPythonString()).join("&&") + ")"; - return ret; + return "(" + this.ValueComparisons.map(vc => vc.ToPythonString()).join("&&") + ")"; } public static And(filters: string[]): string { @@ -84,47 +81,4 @@ export class FilterModel { } return ret; } - - // public static GetFilterModelsRecursive(baseOperation: BaseOperation, - // visitedFilterProviders: Set<IBaseFilterProvider>, filterModels: FilterModel[], isFirst: boolean): string { - // let ret = ""; - // if (Utils.isBaseFilterProvider(baseOperation)) { - // visitedFilterProviders.add(baseOperation); - // let filtered = baseOperation.FilterModels.filter(fm => fm && fm.ValueComparisons.length > 0); - // if (!isFirst && filtered.length > 0) { - // filterModels.push(...filtered); - // ret = "(" + baseOperation.FilterModels.filter(fm => fm != null).map(fm => fm.ToPythonString()).join(" || ") + ")"; - // } - // } - // if (Utils.isBaseFilterConsumer(baseOperation) && baseOperation.Links) { - // let children = new Array<string>(); - // let linkedGraphNodes = baseOperation.Links.get(LinkType.Filter); - // if (linkedGraphNodes != null) { - // for (let i = 0; i < linkedGraphNodes.length; i++) { - // let linkVm = linkedGraphNodes[i].Data; - // let linkedGraphNode = linkedGraphNodes[i].Target; - // if (!visitedFilterProviders.has(linkedGraphNode)) { - // let child = FilterModel.GetFilterModelsRecursive(linkedGraphNode, visitedFilterProviders, filterModels, false); - // if (child !== "") { - // if (linkVm.IsInverted) { - // child = "! " + child; - // } - // children.push(child); - // } - // } - // } - // } - - // let childrenJoined = children.join(baseOperation.FilterOperand === FilterOperand.AND ? " && " : " || "); - // if (children.length > 0) { - // if (ret !== "") { - // ret = "(" + ret + " && (" + childrenJoined + "))"; - // } - // else { - // ret = "(" + childrenJoined + ")"; - // } - // } - // } - // return ret; - // } }
\ No newline at end of file diff --git a/src/client/northstar/operations/BaseOperation.ts b/src/client/northstar/operations/BaseOperation.ts index 4bc8873d5..7db6fcb91 100644 --- a/src/client/northstar/operations/BaseOperation.ts +++ b/src/client/northstar/operations/BaseOperation.ts @@ -61,7 +61,8 @@ export abstract class BaseOperation { } let operationParameters = this.CreateOperationParameters(); - this.Result = undefined; + if (this.Result) + this.Result.progress = 0; // bcz: used to set Result to undefined, but that causes the display to blink this.Error = ""; let salt = Math.random().toString(); this.RequestSalt = salt; diff --git a/src/client/northstar/operations/HistogramOperation.ts b/src/client/northstar/operations/HistogramOperation.ts index 93946b296..bceadb961 100644 --- a/src/client/northstar/operations/HistogramOperation.ts +++ b/src/client/northstar/operations/HistogramOperation.ts @@ -55,7 +55,6 @@ export class HistogramOperation extends BaseOperation implements IBaseFilterCons public get FilterString(): string { let filterModels: FilterModel[] = []; let fstring = FilterModel.GetFilterModelsRecursive(this, new Set<IBaseFilterProvider>(), filterModels, true) - console.log("Filter string " + this.X.AttributeModel.DisplayName + " = " + fstring); return fstring; } @computed diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index 12d14eb42..40990b76a 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -20,6 +20,7 @@ import { PDFBox } from "./PDFBox"; import { VideoBox } from "./VideoBox"; import { WebBox } from "./WebBox"; import { HistogramBox } from "./HistogramBox"; +import { HistogramBoxPrimitives } from "./HistogramBoxPrimitives"; import React = require("react"); const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this? @@ -52,7 +53,7 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & { return <p>Error loading layout keys</p>; } return <JsxParser - components={{ FormattedTextBox, ImageBox, CollectionFreeFormView, CollectionDockingView, CollectionSchemaView, CollectionView, CollectionPDFView, CollectionVideoView, WebBox, KeyValueBox, PDFBox, VideoBox, AudioBox, HistogramBox }} + components={{ FormattedTextBox, ImageBox, CollectionFreeFormView, CollectionDockingView, CollectionSchemaView, CollectionView, CollectionPDFView, CollectionVideoView, WebBox, KeyValueBox, PDFBox, VideoBox, AudioBox, HistogramBox, HistogramBoxPrimitives }} bindings={this.CreateBindings()} jsx={this.layout} showWarnings={true} diff --git a/src/client/views/nodes/HistogramBox.tsx b/src/client/views/nodes/HistogramBox.tsx index e21054e15..20a022227 100644 --- a/src/client/views/nodes/HistogramBox.tsx +++ b/src/client/views/nodes/HistogramBox.tsx @@ -13,16 +13,15 @@ import { FilterModel } from '../../northstar/core/filter/FilterModel'; import { NominalVisualBinRange } from "../../northstar/model/binRanges/NominalVisualBinRange"; import { ChartType, VisualBinRange } from '../../northstar/model/binRanges/VisualBinRange'; import { VisualBinRangeHelper } from "../../northstar/model/binRanges/VisualBinRangeHelper"; -import { AggregateBinRange, AggregateFunction, Bin, BinRange, Brush, DoubleValueAggregateResult, HistogramResult, MarginAggregateParameters, MarginAggregateResult } from "../../northstar/model/idea/idea"; +import { AggregateBinRange, BinRange, DoubleValueAggregateResult, HistogramResult } from "../../northstar/model/idea/idea"; import { ModelHelpers } from "../../northstar/model/ModelHelpers"; import { HistogramOperation } from "../../northstar/operations/HistogramOperation"; -import { ArrayUtil } from "../../northstar/utils/ArrayUtil"; -import { LABColor } from '../../northstar/utils/LABcolor'; import { PIXIRectangle } from "../../northstar/utils/MathUtil"; import { SizeConverter } from "../../northstar/utils/SizeConverter"; import { StyleConstants } from "../../northstar/utils/StyleContants"; import { FieldView, FieldViewProps } from './FieldView'; import "./HistogramBox.scss"; +import { HistogramBoxPrimitives } from './HistogramBoxPrimitives'; @observer export class HistogramBox extends React.Component<FieldViewProps> { @@ -41,6 +40,7 @@ export class HistogramBox extends React.Component<FieldViewProps> { @computed get xaxislines() { return this.renderGridLinesAndLabels(0); } @computed get yaxislines() { return this.renderGridLinesAndLabels(1); } + @computed get createOperationParamsCache() { return this.HistoOp!.CreateOperationParameters(); } componentDidMount() { reaction(() => [CurrentUserUtils.ActiveSchemaName, this.props.doc.GetText(KeyStore.NorthstarSchema, "?")], @@ -57,8 +57,8 @@ export class HistogramBox extends React.Component<FieldViewProps> { binRanges[1] instanceof AggregateBinRange ? ChartType.VerticalBar : ChartType.HeatMap; this.VisualBinRanges.length = 0; - this.VisualBinRanges.push(VisualBinRangeHelper.GetVisualBinRange(binRanges[0], this.HistoOp.Result, this.HistoOp.X, this.ChartType)); - this.VisualBinRanges.push(VisualBinRangeHelper.GetVisualBinRange(binRanges[1], this.HistoOp.Result, this.HistoOp.Y, this.ChartType)); + this.VisualBinRanges.push(VisualBinRangeHelper.GetVisualBinRange(binRanges[0], this.HistoOp!.Result!, this.HistoOp!.X, this.ChartType)); + this.VisualBinRanges.push(VisualBinRangeHelper.GetVisualBinRange(binRanges[1], this.HistoOp!.Result!, this.HistoOp!.Y, this.ChartType)); if (!this.HistoOp.Result.isEmpty) { this.MaxValue = Number.MIN_VALUE; @@ -79,11 +79,6 @@ export class HistogramBox extends React.Component<FieldViewProps> { ); } - @computed - get createOperationParamsCache() { - return this.HistoOp!.CreateOperationParameters(); - } - activateHistogramOperation() { this.props.doc.GetTAsync(this.props.fieldKey, HistogramField).then((histoOp: Opt<HistogramField>) => { if (histoOp) { @@ -91,7 +86,7 @@ export class HistogramBox extends React.Component<FieldViewProps> { this.HistoOp!.Update(); reaction( () => this.createOperationParamsCache, - () => this.HistoOp!.Update(); + () => this.HistoOp!.Update()); reaction(() => this.props.doc.GetList(KeyStore.LinkedFromDocs, []), (docs: Document[]) => { this.HistoOp!.Links.length = 0; @@ -107,22 +102,16 @@ export class HistogramBox extends React.Component<FieldViewProps> { return <div key={DashUtils.GenerateGuid()} style={{ position: "absolute", width: `${width}px`, height: `${height}px`, background: "lightgray", transform: `translate(${xFrom}px, ${yFrom}px)` }} />; } - drawRect(r: PIXIRectangle, color: number, tapHandler: () => void) { - return <div key={DashUtils.GenerateGuid()} onPointerDown={tapHandler} style={{ position: "absolute", transform: `translate(${r.x}px,${r.y}px)`, width: `${r.width - 1}`, height: `${r.height}`, background: LABColor.RGBtoHexString(color) }} /> - } - private renderGridLinesAndLabels(axis: number) { let sc = this.SizeConverter!; - let labels = this.VisualBinRanges[axis].GetLabels(); - - let dim = sc.RenderSize[axis] / sc.MaxLabelSizes[axis].coords[axis] + 5; - let mod = Math.ceil(labels.length / dim); + if (!sc || !this.VisualBinRanges.length) + return (null); + let dim = sc.RenderSize[axis] / ((axis == 0 && this.VisualBinRanges[axis] instanceof NominalVisualBinRange) ? + (12 + 5) : // (<number>FontStyles.AxisLabel.fontSize + 5))); + sc.MaxLabelSizes[axis].coords[axis] + 5); - if (axis == 0 && this.VisualBinRanges[axis] instanceof NominalVisualBinRange) { - mod = Math.ceil( - labels.length / (sc.RenderSize[0] / (12 + 5))); // (<number>FontStyles.AxisLabel.fontSize + 5))); - } let prims: JSX.Element[] = []; + let labels = this.VisualBinRanges[axis].GetLabels(); labels.map((binLabel, i) => { let xFrom = sc.DataToScreenX(axis === 0 ? binLabel.minValue! : sc.DataMins[0]); let xTo = sc.DataToScreenX(axis === 0 ? binLabel.maxValue! : sc.DataMaxs[0]); @@ -133,7 +122,7 @@ export class HistogramBox extends React.Component<FieldViewProps> { if (i == labels.length - 1) prims.push(this.drawLine(axis == 0 ? xTo : xFrom, axis == 0 ? yFrom : yTo, axis == 0 ? 1 : xTo - xFrom, axis == 0 ? yTo - yFrom : 1)); - if (i % mod === 0 && binLabel.label) { + if (i % Math.ceil(labels.length / dim) === 0 && binLabel.label) { let text = binLabel.label; if (text.length >= StyleConstants.MAX_CHAR_FOR_HISTOGRAM_LABELS) { text = text.slice(0, StyleConstants.MAX_CHAR_FOR_HISTOGRAM_LABELS - 3) + "..."; @@ -157,330 +146,21 @@ export class HistogramBox extends React.Component<FieldViewProps> { return prims; } - @computed - get binPrimitives() { - if (!this.HistoOp || !(this.HistoOp.Result instanceof HistogramResult) || !this.SizeConverter) - return undefined; - let prims: JSX.Element[] = []; - let selectedBinPrimitiveCollections = new Array<HistogramBinPrimitiveCollection>(); - let allBrushIndex = ModelHelpers.AllBrushIndex(this.HistoOp.Result); - for (let key in this.HistoOp.Result.bins) { - if (this.HistoOp.Result.bins.hasOwnProperty(key)) { - let drawPrims = new HistogramBinPrimitiveCollection(key, this); - - let filterModel = ModelHelpers.GetBinFilterModel(this.HistoOp.Result.bins![key], allBrushIndex, this.HistoOp.Result, this.HistoOp.X, this.HistoOp.Y); - - this.HitTargets.setValue(drawPrims.HitGeom, filterModel); - - if (ArrayUtil.Contains(this.HistoOp.FilterModels, filterModel)) { - selectedBinPrimitiveCollections.push(drawPrims); - } - - drawPrims.BinPrimitives.filter(bp => bp.DataValue && bp.BrushIndex !== allBrushIndex).map(binPrimitive => { - let toggleFilter = () => { - if ([filterModel].filter(h => ArrayUtil.Contains(this.HistoOp!.FilterModels, h)).length > 0) - this.HistoOp!.RemoveFilterModels([filterModel]); - else this.HistoOp!.AddFilterModels([filterModel]); - } - prims.push(this.drawRect(binPrimitive.Rect, binPrimitive.Color, () => runInAction(toggleFilter))); - prims.push(this.drawRect(binPrimitive.MarginRect, StyleConstants.MARGIN_BARS_COLOR, () => runInAction(toggleFilter))); - }); - } - } - return prims; - } - render() { - trace(); - if (!this.binPrimitives || !this.VisualBinRanges.length) { - return (null); - } - + let label = this.HistoOp && this.HistoOp.X ? this.HistoOp.X.AttributeModel.DisplayName : "<...>"; + let xaxislines = this.xaxislines; + let yaxislines = this.yaxislines; return ( <Measure onResize={(r: any) => runInAction(() => { this._panelWidth = r.entry.width; this._panelHeight = r.entry.height })}> {({ measureRef }) => <div className="histogrambox-container" ref={measureRef} style={{ transform: `translate(${-this.props.doc.GetNumber(KeyStore.Width, 0) / 2}px, ${-this.props.doc.GetNumber(KeyStore.Height, 0) / 2}px)` }}> - {this.xaxislines} - {this.yaxislines} - {this.binPrimitives} - <div className="histogrambox-xaxislabel">{this.HistoOp!.X.AttributeModel.DisplayName}</div> + {xaxislines} + {yaxislines} + <HistogramBoxPrimitives HistoBox={this} /> + <div className="histogrambox-xaxislabel">{label}</div> </div> } </Measure> ) } -} - -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; -} - -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; } - public BinPrimitives: Array<HistogramBinPrimitive> = new Array<HistogramBinPrimitive>(); - public HitGeom: PIXIRectangle = PIXIRectangle.EMPTY; - - constructor(key: string, histoBox: HistogramBox) { - this._histoBox = histoBox; - let bin = this.histoResult.bins![key]; - - var overlapBrushIndex = ModelHelpers.OverlapBrushIndex(this.histoResult); - var orderedBrushes = new Array<Brush>(); - orderedBrushes.push(this.histoResult.brushes![0]); - orderedBrushes.push(this.histoResult.brushes![overlapBrushIndex]); - for (var b = 0; b < this.histoResult.brushes!.length; b++) { - var brush = this.histoResult.brushes![b]; - if (brush.brushIndex != 0 && brush.brushIndex != overlapBrushIndex) { - orderedBrushes.push(brush); - } - } - var binBrushMaxAxis = this.getBinBrushAxisRange(bin, orderedBrushes, this.histoOp.Normalization); // X= 0, Y = 1 - - var brushFactorSum: number = 0; - for (var b = 0; b < orderedBrushes.length; b++) { - var brush = orderedBrushes[b]; - var valueAggregateKey = ModelHelpers.CreateAggregateKey(this.histoOp.V, this.histoResult, brush.brushIndex!); - var doubleRes = ModelHelpers.GetAggregateResult(bin, valueAggregateKey) as DoubleValueAggregateResult; - var unNormalizedValue = (doubleRes != null && doubleRes.hasResult) ? doubleRes.result : null; - if (unNormalizedValue) - switch (histoBox.ChartType) { - case ChartType.VerticalBar: - this.createVerticalBarChartBinPrimitives(bin, brush, binBrushMaxAxis, this.histoOp.Normalization, histoBox.SizeConverter!); // X = 0, Y = 1, NOne = -1 - break; - case ChartType.HorizontalBar: - this.createHorizontalBarChartBinPrimitives(bin, brush, binBrushMaxAxis, this.histoOp.Normalization, histoBox.SizeConverter!); - break; - case ChartType.SinglePoint: - this.createSinlgePointChartBinPrimitives(bin, brush, unNormalizedValue, histoBox.SizeConverter!); - break; - case ChartType.HeatMap: - var normalizedValue = (unNormalizedValue - histoBox.MinValue) / (Math.abs((histoBox.MaxValue - histoBox.MinValue)) < HistogramBinPrimitiveCollection.TOLERANCE ? - unNormalizedValue : histoBox.MaxValue - histoBox.MinValue); - brushFactorSum = this.createHeatmapBinPrimitives(bin, brush, unNormalizedValue, brushFactorSum, normalizedValue, histoBox.SizeConverter!); - } - } - - // adjust brush rects (stacking or not) - var sum: number = 0; - var allBrushIndex = ModelHelpers.AllBrushIndex(this.histoResult); - var filteredBinPrims = this.BinPrimitives.filter(b => b.BrushIndex != allBrushIndex && b.DataValue != 0.0); - var count: number = filteredBinPrims.length; - filteredBinPrims.map(fbp => { - if (histoBox.ChartType == ChartType.VerticalBar) { - if (this.histoOp.X.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); - 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 / count, 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); - 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); - 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 / count); - fbp.MarginRect = new PIXIRectangle(fbp.MarginRect.x, fbp.MarginRect.y - h + sum + (fbp.Rect.height / 2.0), fbp.MarginRect.width, fbp.MarginRect.height); - sum += fbp.Rect.height; - } - } - }); - 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 getBinBrushAxisRange(bin: Bin, brushes: Array<Brush>, axis: number): number { - var binBrushMaxAxis = Number.MIN_VALUE; - brushes.forEach((Brush) => { - var maxAggregateKey = ModelHelpers.CreateAggregateKey(axis === 0 ? this.histoOp.Y : this.histoOp.X, this.histoResult, Brush.brushIndex!); - var aggResult = ModelHelpers.GetAggregateResult(bin, maxAggregateKey) as DoubleValueAggregateResult; - if (aggResult != null) { - if (aggResult.result! > binBrushMaxAxis) - binBrushMaxAxis = aggResult.result!; - } - }); - return binBrushMaxAxis; - } - private createHeatmapBinPrimitives(bin: Bin, brush: Brush, unNormalizedValue: number, brushFactorSum: number, normalizedValue: number, sizeConverter: SizeConverter): number { - - var valueAggregateKey = ModelHelpers.CreateAggregateKey(this.histoOp.V, this.histoResult, ModelHelpers.AllBrushIndex(this.histoResult)); - var allUnNormalizedValue = ModelHelpers.GetAggregateResult(bin, valueAggregateKey) as DoubleValueAggregateResult; - - var tx = this._histoBox.VisualBinRanges[0].GetValueFromIndex(bin.binIndex!.indices![0]); - var xFrom = sizeConverter.DataToScreenX(tx); - var xTo = sizeConverter.DataToScreenX(this._histoBox.VisualBinRanges[0].AddStep(tx)); - - var ty = this._histoBox.VisualBinRanges[1].GetValueFromIndex(bin.binIndex!.indices![1]); - var yFrom = sizeConverter.DataToScreenY(ty); - var yTo = sizeConverter.DataToScreenY(this._histoBox.VisualBinRanges[1].AddStep(ty)); - - var returnBrushFactorSum = brushFactorSum; - if (allUnNormalizedValue.hasResult) { - var brushFactor = (unNormalizedValue / allUnNormalizedValue.result!); - 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(bin, brush, PIXIRectangle.EMPTY, 0, xFrom, xTo, yFrom, yTo, dataColor, 1, unNormalizedValue); - return returnBrushFactorSum; - } - - private createSinlgePointChartBinPrimitives(bin: Bin, brush: Brush, unNormalizedValue: number, sizeConverter: SizeConverter): void { - var yAggregateKey = ModelHelpers.CreateAggregateKey(this.histoOp.Y, this.histoResult, brush.brushIndex!); - var xAggregateKey = ModelHelpers.CreateAggregateKey(this.histoOp.X, this.histoResult, brush.brushIndex!); - - var xValue = ModelHelpers.GetAggregateResult(bin, xAggregateKey) as DoubleValueAggregateResult; - if (!xValue.hasResult) - return; - var xFrom = sizeConverter.DataToScreenX(xValue.result!) - 5; - var xTo = sizeConverter.DataToScreenX(xValue.result!) + 5; - - var yValue = ModelHelpers.GetAggregateResult(bin, yAggregateKey) as DoubleValueAggregateResult;; - if (!yValue.hasResult) - return; - var yFrom = sizeConverter.DataToScreenY(yValue.result!) + 5; - var yTo = sizeConverter.DataToScreenY(yValue.result!); - - this.createBinPrimitive(bin, brush, PIXIRectangle.EMPTY, 0, xFrom, xTo, yFrom, yTo, this.baseColorFromBrush(brush), 1, unNormalizedValue); - } - - private createVerticalBarChartBinPrimitives(bin: Bin, brush: Brush, binBrushMaxAxis: number, normalization: number, sizeConverter: SizeConverter): void { - var yAggregateKey = ModelHelpers.CreateAggregateKey(this.histoOp.Y, this.histoResult, brush.brushIndex!); - var marginParams = new MarginAggregateParameters(); - marginParams.aggregateFunction = this.histoOp.Y.AggregateFunction; - var yMarginAggregateKey = ModelHelpers.CreateAggregateKey(this.histoOp.Y, this.histoResult, - brush.brushIndex!, marginParams); - var dataValue = ModelHelpers.GetAggregateResult(bin, yAggregateKey) as DoubleValueAggregateResult; - - if (dataValue != null && dataValue.hasResult) { - var yValue = normalization != 0 || binBrushMaxAxis == 0 ? dataValue.result! : (dataValue.result! - 0) / (binBrushMaxAxis - 0) * sizeConverter.DataRanges[1]; - - var yFrom = sizeConverter.DataToScreenY(Math.min(0, yValue)); - var yTo = sizeConverter.DataToScreenY(Math.max(0, yValue));; - - var xValue = this._histoBox.VisualBinRanges[0].GetValueFromIndex(bin.binIndex!.indices![0])!; - var xFrom = sizeConverter.DataToScreenX(xValue); - var xTo = sizeConverter.DataToScreenX(this._histoBox.VisualBinRanges[0].AddStep(xValue)); - - var marginResult = ModelHelpers.GetAggregateResult(bin, yMarginAggregateKey) as MarginAggregateResult; - var yMarginAbsolute = !marginResult ? 0 : marginResult.absolutMargin!; - var marginRect = new PIXIRectangle(xFrom + (xTo - xFrom) / 2.0 - 1, - sizeConverter.DataToScreenY(yValue + yMarginAbsolute), 2, - sizeConverter.DataToScreenY(yValue - yMarginAbsolute) - sizeConverter.DataToScreenY(yValue + yMarginAbsolute)); - - this.createBinPrimitive(bin, brush, marginRect, 0, xFrom, xTo, yFrom, yTo, - this.baseColorFromBrush(brush), normalization != 0 ? 1 : 0.6 * binBrushMaxAxis / sizeConverter.DataRanges[1] + 0.4, dataValue.result!); - } - } - - private createHorizontalBarChartBinPrimitives(bin: Bin, brush: Brush, binBrushMaxAxis: number, normalization: number, sizeConverter: SizeConverter): void { - var xAggregateKey = ModelHelpers.CreateAggregateKey(this.histoOp.X, this.histoResult, brush.brushIndex!); - var marginParams = new MarginAggregateParameters(); - marginParams.aggregateFunction = this.histoOp.X.AggregateFunction; - var xMarginAggregateKey = ModelHelpers.CreateAggregateKey(this.histoOp.X, this.histoResult, - brush.brushIndex!, marginParams); - var dataValue = ModelHelpers.GetAggregateResult(bin, xAggregateKey) as DoubleValueAggregateResult; - - if (dataValue != null && dataValue.hasResult) { - var xValue = normalization != 1 || binBrushMaxAxis == 0 ? dataValue.result! : (dataValue.result! - 0) / (binBrushMaxAxis - 0) * sizeConverter.DataRanges[0]; - var xFrom = sizeConverter.DataToScreenX(Math.min(0, xValue)); - var xTo = sizeConverter.DataToScreenX(Math.max(0, xValue)); - - var yValue = this._histoBox.VisualBinRanges[1].GetValueFromIndex(bin.binIndex!.indices![1]); - var yFrom = yValue; - var yTo = this._histoBox.VisualBinRanges[1].AddStep(yValue); - - var marginResult = ModelHelpers.GetAggregateResult(bin, xMarginAggregateKey) as MarginAggregateResult; - var xMarginAbsolute = sizeConverter.IsSmall || !marginResult ? 0 : marginResult.absolutMargin!; - - var marginRect = new PIXIRectangle(sizeConverter.DataToScreenX(xValue - xMarginAbsolute), - yTo + (yFrom - yTo) / 2.0 - 1, - sizeConverter.DataToScreenX(xValue + xMarginAbsolute) - sizeConverter.DataToScreenX(xValue - xMarginAbsolute), - 2.0); - - this.createBinPrimitive(bin, brush, marginRect, 0, xFrom, xTo, yFrom, yTo, - this.baseColorFromBrush(brush), normalization != 1 ? 1 : 0.6 * binBrushMaxAxis / sizeConverter.DataRanges[0] + 0.4, dataValue.result!); - } - } - - private createBinPrimitive(bin: Bin, brush: Brush, marginRect: PIXIRectangle, - marginPercentage: number, xFrom: number, xTo: number, yFrom: number, yTo: number, color: number, opacity: number, dataValue: number) { - // hitgeom todo - - 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 - }); - this.BinPrimitives.push(binPrimitive); - } - - private baseColorFromBrush(brush: Brush): number { - var baseColor: number = StyleConstants.HIGHLIGHT_COLOR; - if (brush.brushIndex == ModelHelpers.RestBrushIndex(this.histoResult)) { - baseColor = StyleConstants.HIGHLIGHT_COLOR; - } - else if (brush.brushIndex == ModelHelpers.OverlapBrushIndex(this.histoResult)) { - baseColor = StyleConstants.OVERLAP_COLOR; - } - else if (brush.brushIndex == ModelHelpers.AllBrushIndex(this.histoResult)) { - baseColor = 0x00ff00; - } - else { - if (this._histoBox.HistoOp!.BrushColors.length > 0) { - baseColor = this._histoBox.HistoOp!.BrushColors[brush.brushIndex! % this._histoBox.HistoOp!.BrushColors.length]; - } - else { - baseColor = StyleConstants.HIGHLIGHT_COLOR; - } - } - return baseColor; - } }
\ No newline at end of file diff --git a/src/client/views/nodes/HistogramBoxPrimitives.tsx b/src/client/views/nodes/HistogramBoxPrimitives.tsx new file mode 100644 index 000000000..2f4a553b7 --- /dev/null +++ b/src/client/views/nodes/HistogramBoxPrimitives.tsx @@ -0,0 +1,373 @@ +import React = require("react") +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 { SizeConverter } from "../../northstar/utils/SizeConverter"; +import { StyleConstants } from "../../northstar/utils/StyleContants"; +import "./HistogramBox.scss"; +import { HistogramBox } from "./HistogramBox"; +import { computed, runInAction, observable, trace } from "mobx"; +import { ArrayUtil } from "../../northstar/utils/ArrayUtil"; +import { Utils as DashUtils } from '../../../Utils'; +import { observer } from "mobx-react"; + + +export interface HistogramBoxPrimitivesProps { + HistoBox: HistogramBox; +} + +@observer +export class HistogramBoxPrimitives extends React.Component<HistogramBoxPrimitivesProps> { + @observable _selectedPrims: HistogramBinPrimitive[] = []; + + @computed + get selectedPrimitives() { + return this._selectedPrims.map((bp) => this.drawBorder(bp.Rect, StyleConstants.OPERATOR_BACKGROUND_COLOR)); + } + @computed + get binPrimitives() { + if (!this.props.HistoBox.HistoOp || !(this.props.HistoBox.HistoOp.Result instanceof HistogramResult) || !this.props.HistoBox.SizeConverter) + return (null); + let prims: JSX.Element[] = []; + let allBrushIndex = ModelHelpers.AllBrushIndex(this.props.HistoBox.HistoOp.Result); + for (let key in this.props.HistoBox.HistoOp.Result.bins) { + if (this.props.HistoBox.HistoOp.Result.bins.hasOwnProperty(key)) { + let drawPrims = new HistogramBinPrimitiveCollection(key, this.props.HistoBox); + let filterModel = ModelHelpers.GetBinFilterModel(this.props.HistoBox.HistoOp.Result.bins![key], allBrushIndex, this.props.HistoBox.HistoOp.Result, this.props.HistoBox.HistoOp.X, this.props.HistoBox.HistoOp.Y); + + this.props.HistoBox.HitTargets.setValue(drawPrims.HitGeom, filterModel); + + drawPrims.BinPrimitives.filter(bp => bp.DataValue && bp.BrushIndex !== allBrushIndex).map(binPrimitive => { + let toggleFilter = () => { + if ([filterModel].filter(h => ArrayUtil.Contains(this.props.HistoBox.HistoOp!.FilterModels, h)).length > 0) { + let bp = ArrayUtil.FirstOrDefault<HistogramBinPrimitive>(drawPrims.BinPrimitives, (bp: HistogramBinPrimitive) => bp.BrushIndex == allBrushIndex); + if (bp && bp.DataValue) { + this._selectedPrims.splice(this._selectedPrims.indexOf(bp), 1); + } + this.props.HistoBox.HistoOp!.RemoveFilterModels([filterModel]); + } + else { + let bp = ArrayUtil.FirstOrDefault<HistogramBinPrimitive>(drawPrims.BinPrimitives, (bp: HistogramBinPrimitive) => bp.BrushIndex == allBrushIndex); + if (bp && bp.DataValue) { + this._selectedPrims.push(bp!); + } + this.props.HistoBox.HistoOp!.AddFilterModels([filterModel]); + } + } + prims.push(this.drawRect(binPrimitive.Rect, binPrimitive.Color, () => runInAction(toggleFilter))); + prims.push(this.drawRect(binPrimitive.MarginRect, StyleConstants.MARGIN_BARS_COLOR, () => runInAction(toggleFilter))); + }); + } + } + return prims; + } + drawBorder(r: PIXIRectangle, color: number) { + return <div key={DashUtils.GenerateGuid()} className="histogramboxprimitive-border" + style={{ + position: "absolute", + transform: `translate(${r.x}px,${r.y}px)`, + width: `${r.width - 1}`, + height: `${r.height}`, + border: "1px", + borderStyle: "solid", + pointerEvents: "none", + borderColor: `${LABColor.RGBtoHexString(color)}` + }} + /> + } + + drawRect(r: PIXIRectangle, color: number, tapHandler: () => void) { + return <div key={DashUtils.GenerateGuid()} onPointerDown={tapHandler} + style={{ + position: "absolute", + transform: `translate(${r.x}px,${r.y}px)`, + width: `${r.width - 1}`, + height: `${r.height}`, + background: `${LABColor.RGBtoHexString(color)}` + }} + /> + } + render() { + return <div> + {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; +} + +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; } + public BinPrimitives: Array<HistogramBinPrimitive> = new Array<HistogramBinPrimitive>(); + public HitGeom: PIXIRectangle = PIXIRectangle.EMPTY; + + constructor(key: string, histoBox: HistogramBox) { + this._histoBox = histoBox; + let bin = this.histoResult.bins![key]; + + var overlapBrushIndex = ModelHelpers.OverlapBrushIndex(this.histoResult); + var orderedBrushes = new Array<Brush>(); + orderedBrushes.push(this.histoResult.brushes![0]); + orderedBrushes.push(this.histoResult.brushes![overlapBrushIndex]); + for (var b = 0; b < this.histoResult.brushes!.length; b++) { + var brush = this.histoResult.brushes![b]; + if (brush.brushIndex != 0 && brush.brushIndex != overlapBrushIndex) { + orderedBrushes.push(brush); + } + } + var binBrushMaxAxis = this.getBinBrushAxisRange(bin, orderedBrushes, this.histoOp.Normalization); // X= 0, Y = 1 + + var brushFactorSum: number = 0; + for (var b = 0; b < orderedBrushes.length; b++) { + var brush = orderedBrushes[b]; + var valueAggregateKey = ModelHelpers.CreateAggregateKey(this.histoOp.V, this.histoResult, brush.brushIndex!); + var doubleRes = ModelHelpers.GetAggregateResult(bin, valueAggregateKey) as DoubleValueAggregateResult; + var unNormalizedValue = (doubleRes != null && doubleRes.hasResult) ? doubleRes.result : null; + if (unNormalizedValue) + switch (histoBox.ChartType) { + case ChartType.VerticalBar: + this.createVerticalBarChartBinPrimitives(bin, brush, binBrushMaxAxis, this.histoOp.Normalization, histoBox.SizeConverter!); // X = 0, Y = 1, NOne = -1 + break; + case ChartType.HorizontalBar: + this.createHorizontalBarChartBinPrimitives(bin, brush, binBrushMaxAxis, this.histoOp.Normalization, histoBox.SizeConverter!); + break; + case ChartType.SinglePoint: + this.createSinlgePointChartBinPrimitives(bin, brush, unNormalizedValue, histoBox.SizeConverter!); + break; + case ChartType.HeatMap: + var normalizedValue = (unNormalizedValue - histoBox.MinValue) / (Math.abs((histoBox.MaxValue - histoBox.MinValue)) < HistogramBinPrimitiveCollection.TOLERANCE ? + unNormalizedValue : histoBox.MaxValue - histoBox.MinValue); + brushFactorSum = this.createHeatmapBinPrimitives(bin, brush, unNormalizedValue, brushFactorSum, normalizedValue, histoBox.SizeConverter!); + } + } + + // adjust brush rects (stacking or not) + var sum: number = 0; + var allBrushIndex = ModelHelpers.AllBrushIndex(this.histoResult); + var filteredBinPrims = this.BinPrimitives.filter(b => b.BrushIndex != allBrushIndex && b.DataValue != 0.0); + var count: number = filteredBinPrims.length; + filteredBinPrims.map(fbp => { + if (histoBox.ChartType == ChartType.VerticalBar) { + if (this.histoOp.X.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); + 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 / count, 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); + 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); + 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 / count); + fbp.MarginRect = new PIXIRectangle(fbp.MarginRect.x, fbp.MarginRect.y - h + sum + (fbp.Rect.height / 2.0), fbp.MarginRect.width, fbp.MarginRect.height); + sum += fbp.Rect.height; + } + } + }); + 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 getBinBrushAxisRange(bin: Bin, brushes: Array<Brush>, axis: number): number { + var binBrushMaxAxis = Number.MIN_VALUE; + brushes.forEach((Brush) => { + var maxAggregateKey = ModelHelpers.CreateAggregateKey(axis === 0 ? this.histoOp.Y : this.histoOp.X, this.histoResult, Brush.brushIndex!); + var aggResult = ModelHelpers.GetAggregateResult(bin, maxAggregateKey) as DoubleValueAggregateResult; + if (aggResult != null) { + if (aggResult.result! > binBrushMaxAxis) + binBrushMaxAxis = aggResult.result!; + } + }); + return binBrushMaxAxis; + } + private createHeatmapBinPrimitives(bin: Bin, brush: Brush, unNormalizedValue: number, brushFactorSum: number, normalizedValue: number, sizeConverter: SizeConverter): number { + + var valueAggregateKey = ModelHelpers.CreateAggregateKey(this.histoOp.V, this.histoResult, ModelHelpers.AllBrushIndex(this.histoResult)); + var allUnNormalizedValue = ModelHelpers.GetAggregateResult(bin, valueAggregateKey) as DoubleValueAggregateResult; + + var tx = this._histoBox.VisualBinRanges[0].GetValueFromIndex(bin.binIndex!.indices![0]); + var xFrom = sizeConverter.DataToScreenX(tx); + var xTo = sizeConverter.DataToScreenX(this._histoBox.VisualBinRanges[0].AddStep(tx)); + + var ty = this._histoBox.VisualBinRanges[1].GetValueFromIndex(bin.binIndex!.indices![1]); + var yFrom = sizeConverter.DataToScreenY(ty); + var yTo = sizeConverter.DataToScreenY(this._histoBox.VisualBinRanges[1].AddStep(ty)); + + var returnBrushFactorSum = brushFactorSum; + if (allUnNormalizedValue.hasResult) { + var brushFactor = (unNormalizedValue / allUnNormalizedValue.result!); + 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(bin, brush, PIXIRectangle.EMPTY, 0, xFrom, xTo, yFrom, yTo, dataColor, 1, unNormalizedValue); + return returnBrushFactorSum; + } + + private createSinlgePointChartBinPrimitives(bin: Bin, brush: Brush, unNormalizedValue: number, sizeConverter: SizeConverter): void { + var yAggregateKey = ModelHelpers.CreateAggregateKey(this.histoOp.Y, this.histoResult, brush.brushIndex!); + var xAggregateKey = ModelHelpers.CreateAggregateKey(this.histoOp.X, this.histoResult, brush.brushIndex!); + + var xValue = ModelHelpers.GetAggregateResult(bin, xAggregateKey) as DoubleValueAggregateResult; + if (!xValue.hasResult) + return; + var xFrom = sizeConverter.DataToScreenX(xValue.result!) - 5; + var xTo = sizeConverter.DataToScreenX(xValue.result!) + 5; + + var yValue = ModelHelpers.GetAggregateResult(bin, yAggregateKey) as DoubleValueAggregateResult;; + if (!yValue.hasResult) + return; + var yFrom = sizeConverter.DataToScreenY(yValue.result!) + 5; + var yTo = sizeConverter.DataToScreenY(yValue.result!); + + this.createBinPrimitive(bin, brush, PIXIRectangle.EMPTY, 0, xFrom, xTo, yFrom, yTo, this.baseColorFromBrush(brush), 1, unNormalizedValue); + } + + private createVerticalBarChartBinPrimitives(bin: Bin, brush: Brush, binBrushMaxAxis: number, normalization: number, sizeConverter: SizeConverter): void { + var yAggregateKey = ModelHelpers.CreateAggregateKey(this.histoOp.Y, this.histoResult, brush.brushIndex!); + var marginParams = new MarginAggregateParameters(); + marginParams.aggregateFunction = this.histoOp.Y.AggregateFunction; + var yMarginAggregateKey = ModelHelpers.CreateAggregateKey(this.histoOp.Y, this.histoResult, + brush.brushIndex!, marginParams); + var dataValue = ModelHelpers.GetAggregateResult(bin, yAggregateKey) as DoubleValueAggregateResult; + + if (dataValue != null && dataValue.hasResult) { + var yValue = normalization != 0 || binBrushMaxAxis == 0 ? dataValue.result! : (dataValue.result! - 0) / (binBrushMaxAxis - 0) * sizeConverter.DataRanges[1]; + + var yFrom = sizeConverter.DataToScreenY(Math.min(0, yValue)); + var yTo = sizeConverter.DataToScreenY(Math.max(0, yValue));; + + var xValue = this._histoBox.VisualBinRanges[0].GetValueFromIndex(bin.binIndex!.indices![0])!; + var xFrom = sizeConverter.DataToScreenX(xValue); + var xTo = sizeConverter.DataToScreenX(this._histoBox.VisualBinRanges[0].AddStep(xValue)); + + var marginResult = ModelHelpers.GetAggregateResult(bin, yMarginAggregateKey) as MarginAggregateResult; + var yMarginAbsolute = !marginResult ? 0 : marginResult.absolutMargin!; + var marginRect = new PIXIRectangle(xFrom + (xTo - xFrom) / 2.0 - 1, + sizeConverter.DataToScreenY(yValue + yMarginAbsolute), 2, + sizeConverter.DataToScreenY(yValue - yMarginAbsolute) - sizeConverter.DataToScreenY(yValue + yMarginAbsolute)); + + this.createBinPrimitive(bin, brush, marginRect, 0, xFrom, xTo, yFrom, yTo, + this.baseColorFromBrush(brush), normalization != 0 ? 1 : 0.6 * binBrushMaxAxis / sizeConverter.DataRanges[1] + 0.4, dataValue.result!); + } + } + + private createHorizontalBarChartBinPrimitives(bin: Bin, brush: Brush, binBrushMaxAxis: number, normalization: number, sizeConverter: SizeConverter): void { + var xAggregateKey = ModelHelpers.CreateAggregateKey(this.histoOp.X, this.histoResult, brush.brushIndex!); + var marginParams = new MarginAggregateParameters(); + marginParams.aggregateFunction = this.histoOp.X.AggregateFunction; + var xMarginAggregateKey = ModelHelpers.CreateAggregateKey(this.histoOp.X, this.histoResult, + brush.brushIndex!, marginParams); + var dataValue = ModelHelpers.GetAggregateResult(bin, xAggregateKey) as DoubleValueAggregateResult; + + if (dataValue != null && dataValue.hasResult) { + var xValue = normalization != 1 || binBrushMaxAxis == 0 ? dataValue.result! : (dataValue.result! - 0) / (binBrushMaxAxis - 0) * sizeConverter.DataRanges[0]; + var xFrom = sizeConverter.DataToScreenX(Math.min(0, xValue)); + var xTo = sizeConverter.DataToScreenX(Math.max(0, xValue)); + + var yValue = this._histoBox.VisualBinRanges[1].GetValueFromIndex(bin.binIndex!.indices![1]); + var yFrom = yValue; + var yTo = this._histoBox.VisualBinRanges[1].AddStep(yValue); + + var marginResult = ModelHelpers.GetAggregateResult(bin, xMarginAggregateKey) as MarginAggregateResult; + var xMarginAbsolute = sizeConverter.IsSmall || !marginResult ? 0 : marginResult.absolutMargin!; + + var marginRect = new PIXIRectangle(sizeConverter.DataToScreenX(xValue - xMarginAbsolute), + yTo + (yFrom - yTo) / 2.0 - 1, + sizeConverter.DataToScreenX(xValue + xMarginAbsolute) - sizeConverter.DataToScreenX(xValue - xMarginAbsolute), + 2.0); + + this.createBinPrimitive(bin, brush, marginRect, 0, xFrom, xTo, yFrom, yTo, + this.baseColorFromBrush(brush), normalization != 1 ? 1 : 0.6 * binBrushMaxAxis / sizeConverter.DataRanges[0] + 0.4, dataValue.result!); + } + } + + private createBinPrimitive(bin: Bin, brush: Brush, marginRect: PIXIRectangle, + marginPercentage: number, xFrom: number, xTo: number, yFrom: number, yTo: number, color: number, opacity: number, dataValue: number) { + // hitgeom todo + + 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 + }); + this.BinPrimitives.push(binPrimitive); + } + + private baseColorFromBrush(brush: Brush): number { + var baseColor: number = StyleConstants.HIGHLIGHT_COLOR; + if (brush.brushIndex == ModelHelpers.RestBrushIndex(this.histoResult)) { + baseColor = StyleConstants.HIGHLIGHT_COLOR; + } + else if (brush.brushIndex == ModelHelpers.OverlapBrushIndex(this.histoResult)) { + baseColor = StyleConstants.OVERLAP_COLOR; + } + else if (brush.brushIndex == ModelHelpers.AllBrushIndex(this.histoResult)) { + baseColor = 0x00ff00; + } + else { + if (this._histoBox.HistoOp!.BrushColors.length > 0) { + baseColor = this._histoBox.HistoOp!.BrushColors[brush.brushIndex! % this._histoBox.HistoOp!.BrushColors.length]; + } + else { + baseColor = StyleConstants.HIGHLIGHT_COLOR; + } + } + return baseColor; + } +}
\ No newline at end of file |