diff options
Diffstat (limited to 'src/client/views/nodes/HistogramBox.tsx')
-rw-r--r-- | src/client/views/nodes/HistogramBox.tsx | 538 |
1 files changed, 499 insertions, 39 deletions
diff --git a/src/client/views/nodes/HistogramBox.tsx b/src/client/views/nodes/HistogramBox.tsx index cc43899c1..1508b201b 100644 --- a/src/client/views/nodes/HistogramBox.tsx +++ b/src/client/views/nodes/HistogramBox.tsx @@ -1,67 +1,527 @@ import React = require("react") +import { action, computed, observable, reaction } from "mobx"; import { observer } from "mobx-react"; -import { FieldView, FieldViewProps } from './FieldView'; -import "./VideoBox.scss"; -import { observable, reaction } from "mobx"; -import { HistogramOperation } from "../../northstar/operations/HistogramOperation"; +import Measure from "react-measure"; +import { Dictionary } from "typescript-collections"; +import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils"; +import { Utils as DashUtils } from '../../../Utils'; import { ColumnAttributeModel } from "../../northstar/core/attribute/AttributeModel"; import { AttributeTransformationModel } from "../../northstar/core/attribute/AttributeTransformationModel"; -import { AggregateFunction, HistogramResult, DoubleValueAggregateResult } from "../../northstar/model/idea/idea"; +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, Brush, DoubleValueAggregateResult, HistogramResult, MarginAggregateParameters, MarginAggregateResult } from "../../northstar/model/idea/idea"; import { ModelHelpers } from "../../northstar/model/ModelHelpers"; -import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils"; +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"; + + @observer export class HistogramBox extends React.Component<FieldViewProps> { public static LayoutString(fieldStr: string = "DataKey") { return FieldView.LayoutString(HistogramBox, fieldStr) } + @observable private _renderer = []; + @observable private _visualBinRanges: VisualBinRange[] = []; + @observable private _minValue: number = 0; + @observable private _maxValue: number = 0; + @observable private _panelWidth: number = 100; + @observable private _panelHeight: number = 100; + @observable private _histoOp?: HistogramOperation; + @observable private _sizeConverter?: SizeConverter; + @observable private _chartType: ChartType = ChartType.VerticalBar; + public HitTargets: Dictionary<PIXIRectangle, FilterModel> = new Dictionary<PIXIRectangle, FilterModel>(); + + + constructor(props: FieldViewProps) { super(props); } - @observable _histoResult?: HistogramResult; - _histoOp?: HistogramOperation; - componentDidMount() { - CurrentUserUtils.GetAllNorthstarColumnAttributes().map(a => { - if (a.displayName == this.props.doc.Title) { - var atmod = new ColumnAttributeModel(a); - this._histoOp = new HistogramOperation(new AttributeTransformationModel(atmod, AggregateFunction.None), - new AttributeTransformationModel(atmod, AggregateFunction.Count), - new AttributeTransformationModel(atmod, AggregateFunction.Count)); - reaction(() => [this._histoOp && this._histoOp.Result], - () => this._histoResult = this._histoOp ? this._histoOp.Result as HistogramResult : undefined - ); - this._histoOp.Update(); - } - }) - } - - twoString() { - let str = ""; - if (this._histoResult && !this._histoResult.isEmpty) { - for (let key in this._histoResult.bins) { - if (this._histoResult.bins.hasOwnProperty(key)) { - let bin = this._histoResult.bins[key]; - str += JSON.stringify(bin.binIndex!.toJSON()) + " = "; - let valueAggregateKey = ModelHelpers.CreateAggregateKey(this._histoOp!.V, this._histoResult, ModelHelpers.AllBrushIndex(this._histoResult)); - let value = ModelHelpers.GetAggregateResult(bin, valueAggregateKey) as DoubleValueAggregateResult; - if (value && value.hasResult && value.result) { - str += value.result; + reaction(() => [this.props.doc.Title], + () => { + CurrentUserUtils.GetAllNorthstarColumnAttributes().map(a => { + if (a.displayName == this.props.doc.Title) { + var atmod = new ColumnAttributeModel(a); + this._histoOp = new HistogramOperation(new AttributeTransformationModel(atmod, AggregateFunction.None), + new AttributeTransformationModel(atmod, AggregateFunction.Count), + new AttributeTransformationModel(atmod, AggregateFunction.Count)); + this._histoOp.Update(); + } + }); + }, { fireImmediately: true }); + reaction(() => [this._visualBinRanges && this._visualBinRanges.slice(), this._panelHeight, this._panelWidth], + () => this._sizeConverter = new SizeConverter({ x: this._panelWidth, y: this._panelHeight }, this._visualBinRanges, Math.PI / 4)); + reaction(() => [this._histoOp && this._histoOp.Result], + () => { + if (!this._histoOp || !(this._histoOp.Result instanceof HistogramResult) || !this._histoOp.Result.binRanges) + return; + + let binRanges = this._histoOp.Result.binRanges; + this._chartType = binRanges[0] instanceof AggregateBinRange ? (binRanges[1] instanceof AggregateBinRange ? ChartType.SinglePoint : ChartType.HorizontalBar) : + binRanges[1] instanceof AggregateBinRange ? ChartType.VerticalBar : ChartType.HeatMap; + + this._visualBinRanges.length = 0; + this._visualBinRanges.push(VisualBinRangeHelper.GetVisualBinRange(this._histoOp.Result.binRanges![0], this._histoOp.Result, this._histoOp.X, this._chartType)); + this._visualBinRanges.push(VisualBinRangeHelper.GetVisualBinRange(this._histoOp.Result.binRanges![1], this._histoOp.Result, this._histoOp.Y, this._chartType)); + + if (!this._histoOp.Result.isEmpty) { + this._maxValue = Number.MIN_VALUE; + this._minValue = Number.MAX_VALUE; + for (let key in this._histoOp.Result.bins) { + if (this._histoOp.Result.bins.hasOwnProperty(key)) { + let bin = this._histoOp.Result.bins[key]; + let valueAggregateKey = ModelHelpers.CreateAggregateKey(this._histoOp.V, this._histoOp.Result, ModelHelpers.AllBrushIndex(this._histoOp.Result)); + let value = ModelHelpers.GetAggregateResult(bin, valueAggregateKey) as DoubleValueAggregateResult; + if (value && value.hasResult) { + this._maxValue = Math.max(this._maxValue, value.result!); + this._minValue = Math.min(this._minValue, value.result!); + } + } } } } + ); + } + + @computed get xaxislines() { return this.renderGridLinesAndLabels(0); } + @computed get yaxislines() { return this.renderGridLinesAndLabels(1); } + + drawLine(xFrom: number, yFrom: number, width: number, height: number) { + return <div key={DashUtils.GenerateGuid()} + style={{ + position: "absolute", + width: `${width}px`, + height: `${height}px`, + background: "lightgray", + transform: `translate(${xFrom}px, ${yFrom}px)` + }} />; + } + + private renderGridLinesAndLabels(axis: number) { + let prims: JSX.Element[] = []; + 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 (axis == 0 && this._visualBinRanges[axis] instanceof NominalVisualBinRange) { + mod = Math.ceil( + labels.length / (sc.RenderSize[0] / (12 + 5))); // (<number>FontStyles.AxisLabel.fontSize + 5))); } - return str; + for (let i = 0; i < labels.length; i++) { + let binLabel = labels[i]; + let xFrom = sc.DataToScreenX(axis === 0 ? binLabel.minValue! : sc.DataMins[0]); + let xTo = sc.DataToScreenX(axis === 0 ? binLabel.maxValue! : sc.DataMaxs[0]); + let yFrom = sc.DataToScreenY(axis === 0 ? sc.DataMins[1] : binLabel.minValue!); + let yTo = sc.DataToScreenY(axis === 0 ? sc.DataMaxs[1] : binLabel.maxValue!); + + prims.push(this.drawLine(xFrom, yFrom, axis == 0 ? 1 : xTo - xFrom, axis == 0 ? yTo - yFrom : 1)); + 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) { + let text = binLabel.label; + if (text.length >= StyleConstants.MAX_CHAR_FOR_HISTOGRAM_LABELS) { + text = text.slice(0, StyleConstants.MAX_CHAR_FOR_HISTOGRAM_LABELS - 3) + "..."; + } + const textHeight = 14; const textWidth = 30; + let xStart = (axis === 0 ? xFrom + (xTo - xFrom) / 2.0 : xFrom - 10 - textWidth); + let yStart = (axis === 1 ? yFrom - textHeight / 2 : yFrom); + let rotation = 0; + + if (axis == 0 && this._visualBinRanges[axis] instanceof NominalVisualBinRange) { + rotation = Math.min(90, Math.max(30, textWidth / (xTo - xFrom) * 90)); + xStart += Math.max(textWidth / 2, (1 - textWidth / (xTo - xFrom)) * textWidth / 2) - textHeight / 2; + } + + prims.push( + <div key={DashUtils.GenerateGuid()} style={{ position: "absolute", transformOrigin: "left top", transform: `translate(${xStart}px, ${yStart}px) rotate(${rotation}deg)` }}> + {text} + </div>) + } + } + return prims; + } + + @action + setScaling = (r: any) => { + this._panelWidth = r.entry.width; + this._panelHeight = r.entry.height; + } + + @computed + get binPrimitives() { + if (!this._histoOp || !(this._histoOp.Result instanceof HistogramResult)) + return undefined; + let sizeConverter = new SizeConverter({ x: this._panelWidth, y: this._panelHeight, }, this._visualBinRanges, Math.PI / 4); + 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(this._histoOp.Result.bins[key], this._histoOp.Result, + this._histoOp!.V, this._histoOp!.X, this._histoOp!.Y, this._chartType, + this._visualBinRanges, this._minValue, this._maxValue, this._histoOp!.Normalization, sizeConverter); + + this.HitTargets.setValue(drawPrims.HitGeom, drawPrims.FilterModel); + + if (ArrayUtil.Contains(this._histoOp!.FilterModels, drawPrims.FilterModel)) { + selectedBinPrimitiveCollections.push(drawPrims); + } + + drawPrims.BinPrimitives.filter(bp => bp.DataValue && bp.BrushIndex !== allBrushIndex).map(binPrimitive => { + prims.push(this.drawRect(binPrimitive.Rect, binPrimitive.Color)); + prims.push(this.drawRect(binPrimitive.MarginRect, StyleConstants.MARGIN_BARS_COLOR)); + }); + } + } + return prims; + } + + drawRect(rect: PIXIRectangle, color: number) { + return <div key={DashUtils.GenerateGuid()} style={{ + position: "absolute", + transform: `translate(${rect.x}px,${rect.y}px)`, + width: `${rect.width - 1}`, + height: `${rect.height}`, + background: LABColor.RGBtoHexString(color) + }} /> } render() { - if (!this._histoResult) + if (!this.binPrimitives || !this._histoOp || !(this._histoOp.Result instanceof HistogramResult) || !this._visualBinRanges.length) { return (null); + } + return ( - <div className="histogrambox-container"> - `HISTOGRAM RESULT : ${this.twoString()}` - </div> + <Measure onResize={this.setScaling}> + {({ measureRef }) => + <div className="histogrambox-container" ref={measureRef}> + {this.xaxislines} + {this.yaxislines} + {this.binPrimitives} + <div className="histogrambox-xlabel">{this._histoOp!.X.AttributeModel.DisplayName}</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; + + public BinPrimitives: Array<HistogramBinPrimitive> = new Array<HistogramBinPrimitive>(); + public FilterModel: FilterModel; + public HitGeom: PIXIRectangle = PIXIRectangle.EMPTY; + + private _y: AttributeTransformationModel; + private _x: AttributeTransformationModel; + private _value: AttributeTransformationModel; + private _chartType: ChartType; + private _histoResult: HistogramResult; + private _visualBinRanges: Array<VisualBinRange>; + + constructor(bin: Bin, histoResult: HistogramResult, + value: AttributeTransformationModel, x: AttributeTransformationModel, y: AttributeTransformationModel, + chartType: ChartType, visualBinRanges: Array<VisualBinRange>, + minValue: number, maxValue: number, normalization: number, sizeConverter: SizeConverter) { + this._histoResult = histoResult; + this._chartType = chartType; + this._value = value; + this._x = x; + this._y = y; + this._visualBinRanges = visualBinRanges; + + var allBrushIndex = ModelHelpers.AllBrushIndex(this._histoResult); + var overlapBrushIndex = ModelHelpers.OverlapBrushIndex(this._histoResult); + this.FilterModel = ModelHelpers.GetBinFilterModel(bin, allBrushIndex, this._histoResult, this._x, this._y); + + var orderedBrushes = new Array<Brush>(); + orderedBrushes.push(histoResult.brushes![0]); + orderedBrushes.push(histoResult.brushes![overlapBrushIndex]); + for (var b = 0; b < histoResult.brushes!.length; b++) { + var brush = histoResult.brushes![b]; + if (brush.brushIndex != 0 && brush.brushIndex != overlapBrushIndex) { + orderedBrushes.push(brush); + } + } + var binBrushMaxAxis = this.getBinBrushAxisRange(bin, orderedBrushes, 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(value, histoResult, brush.brushIndex!); + var doubleRes = ModelHelpers.GetAggregateResult(bin, valueAggregateKey) as DoubleValueAggregateResult; + var unNormalizedValue = (doubleRes != null && doubleRes.hasResult) ? doubleRes.result : null; + if (unNormalizedValue == null) { + continue; + } + if (chartType == ChartType.VerticalBar) { + this.createVerticalBarChartBinPrimitives(bin, brush, binBrushMaxAxis, normalization, sizeConverter); // X = 0, Y = 1, NOne = -1 + } + else if (chartType == ChartType.HorizontalBar) { + this.createHorizontalBarChartBinPrimitives(bin, brush, binBrushMaxAxis, normalization, sizeConverter); + } + else if (chartType == ChartType.SinglePoint) { + this.createSinlgePointChartBinPrimitives(bin, brush, unNormalizedValue, sizeConverter); + } + else if (chartType == ChartType.HeatMap) { + var normalizedValue = (unNormalizedValue - minValue) / (Math.abs((maxValue - minValue)) < HistogramBinPrimitiveCollection.TOLERANCE ? + unNormalizedValue : (maxValue - minValue)); + brushFactorSum = this.createHeatmapBinPrimitives(bin, brush, unNormalizedValue, brushFactorSum, normalizedValue, sizeConverter); + } + } + + // adjust brush rects (stacking or not) + var sum: number = 0; + var filtered = this.BinPrimitives.filter(b => b.BrushIndex != allBrushIndex && b.DataValue != 0.0); + var count: number = filtered.length; + for (var i = 0; i < count; i++) { + var bp = filtered[i]; + + if (this._chartType == ChartType.VerticalBar) { + if (this._y.AggregateFunction == AggregateFunction.Count) { + bp.Rect = new PIXIRectangle(bp.Rect.x, bp.Rect.y - sum, bp.Rect.width, bp.Rect.height); + bp.MarginRect = new PIXIRectangle(bp.MarginRect.x, bp.MarginRect.y - sum, bp.MarginRect.width, bp.MarginRect.height); + sum += bp.Rect.height; + } + if (this._y.AggregateFunction == AggregateFunction.Avg) { + var w = bp.Rect.width / 2.0; + bp.Rect = new PIXIRectangle(bp.Rect.x + sum, bp.Rect.y, bp.Rect.width / count, bp.Rect.height); + bp.MarginRect = new PIXIRectangle(bp.MarginRect.x - w + sum + (bp.Rect.width / 2.0), bp.MarginRect.y, bp.MarginRect.width, bp.MarginRect.height); + sum += bp.Rect.width; + } + } + else if (this._chartType == ChartType.HorizontalBar) { + if (this._x.AggregateFunction == AggregateFunction.Count) { + bp.Rect = new PIXIRectangle(bp.Rect.x + sum, bp.Rect.y, bp.Rect.width, bp.Rect.height); + bp.MarginRect = new PIXIRectangle(bp.MarginRect.x + sum, bp.MarginRect.y, bp.MarginRect.width, bp.MarginRect.height); + sum += bp.Rect.width; + } + if (this._x.AggregateFunction == AggregateFunction.Avg) { + var h = bp.Rect.height / 2.0; + bp.Rect = new PIXIRectangle(bp.Rect.x, bp.Rect.y + sum, bp.Rect.width, bp.Rect.height / count); + bp.MarginRect = new PIXIRectangle(bp.MarginRect.x, bp.MarginRect.y - h + sum + (bp.Rect.height / 2.0), bp.MarginRect.width, bp.MarginRect.height); + sum += bp.Rect.height; + } + } + else if (this._chartType == ChartType.HeatMap) { + } + } + 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._y : this._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 xFrom: number = 0; + var xTo: number = 0; + var yFrom: number = 0; + var yTo: number = 0; + var returnBrushFactorSum = brushFactorSum; + + var valueAggregateKey = ModelHelpers.CreateAggregateKey(this._value, this._histoResult, ModelHelpers.AllBrushIndex(this._histoResult)); + var allUnNormalizedValue = ModelHelpers.GetAggregateResult(bin, valueAggregateKey) as DoubleValueAggregateResult; + + var tx = this._visualBinRanges[0].GetValueFromIndex(bin.binIndex!.indices![0]); + xFrom = sizeConverter.DataToScreenX(tx); + xTo = sizeConverter.DataToScreenX(this._visualBinRanges[0].AddStep(tx)); + + var ty = this._visualBinRanges[1].GetValueFromIndex(bin.binIndex!.indices![1]); + yFrom = sizeConverter.DataToScreenY(ty); + yTo = sizeConverter.DataToScreenY(this._visualBinRanges[1].AddStep(ty)); + + 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); + + var marginParams = new MarginAggregateParameters(); + marginParams.aggregateFunction = this._value.AggregateFunction; + var marginAggregateKey = ModelHelpers.CreateAggregateKey(this._value, this._histoResult, + ModelHelpers.AllBrushIndex(this._histoResult), marginParams); + + 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._y, this._histoResult, brush.brushIndex!); + var marginParams = new MarginAggregateParameters(); + marginParams.aggregateFunction = this._y.AggregateFunction; + + var xAggregateKey = ModelHelpers.CreateAggregateKey(this._x, this._histoResult, brush.brushIndex!); + var marginParams = new MarginAggregateParameters(); + marginParams.aggregateFunction = this._x.AggregateFunction; + + 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._y, this._histoResult, brush.brushIndex!); + var marginParams = new MarginAggregateParameters(); + marginParams.aggregateFunction = this._y.AggregateFunction; + var yMarginAggregateKey = ModelHelpers.CreateAggregateKey(this._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._visualBinRanges[0].GetValueFromIndex(bin.binIndex!.indices![0])!; + var xFrom = sizeConverter.DataToScreenX(xValue); + var xTo = sizeConverter.DataToScreenX(this._visualBinRanges[0].AddStep(xValue)); + + var marginResult = ModelHelpers.GetAggregateResult(bin, yMarginAggregateKey)!; + var yMarginAbsolute = marginResult == null ? 0 : (marginResult as MarginAggregateResult).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._x, this._histoResult, brush.brushIndex!); + var marginParams = new MarginAggregateParameters(); + marginParams.aggregateFunction = this._x.AggregateFunction; + var xMarginAggregateKey = ModelHelpers.CreateAggregateKey(this._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._visualBinRanges[1].GetValueFromIndex(bin.binIndex!.indices![1]); + var yFrom = yValue; + var yTo = this._visualBinRanges[1].AddStep(yValue); + + var marginResult = ModelHelpers.GetAggregateResult(bin, xMarginAggregateKey); + var xMarginAbsolute = sizeConverter.IsSmall || marginResult == null ? 0 : (marginResult as MarginAggregateResult).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._histogramOperationViewModel.BrushColors.length > 0) { + // baseColor = this._histogramOperationViewModel.BrushColors[brush.brushIndex! % this._histogramOperationViewModel.BrushColors.length]; + // } + // else { + baseColor = StyleConstants.HIGHLIGHT_COLOR; + // } + } + return baseColor; + } }
\ No newline at end of file |