aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorbob <bcz@cs.brown.edu>2019-03-25 16:08:40 -0400
committerbob <bcz@cs.brown.edu>2019-03-25 16:08:40 -0400
commit9d73e6d0a74a5f94e3143203ac10b4397710330c (patch)
tree6593a34600ccf6b7a2b0b6aee7613e40082007b6 /src
parentaec363d4b5fcb3df1a42796014c67dfc52149161 (diff)
parent60ff3da65fbabd21c29bf1eecace02ebc1f6430c (diff)
merged with master
Diffstat (limited to 'src')
-rw-r--r--src/client/northstar/operations/HistogramOperation.ts11
-rw-r--r--src/client/northstar/utils/LABColor.ts90
-rw-r--r--src/client/northstar/utils/MathUtil.ts13
-rw-r--r--src/client/northstar/utils/SizeConverter.ts80
-rw-r--r--src/client/northstar/utils/StyleContants.ts95
-rw-r--r--src/client/views/nodes/HistogramBox.scss6
-rw-r--r--src/client/views/nodes/HistogramBox.tsx538
-rw-r--r--src/mobile/ImageUpload.tsx13
8 files changed, 792 insertions, 54 deletions
diff --git a/src/client/northstar/operations/HistogramOperation.ts b/src/client/northstar/operations/HistogramOperation.ts
index 120a84dad..8367cc725 100644
--- a/src/client/northstar/operations/HistogramOperation.ts
+++ b/src/client/northstar/operations/HistogramOperation.ts
@@ -1,4 +1,4 @@
-import { reaction, computed, action } from "mobx";
+import { reaction, computed, action, observable } from "mobx";
import { Attribute, DataType, QuantitativeBinRange, HistogramOperationParameters, AggregateParameters, AggregateFunction, AverageAggregateParameters } from "../model/idea/idea";
import { ArrayUtil } from "../utils/ArrayUtil";
import { CalculatedAttributeManager } from "../core/attribute/CalculatedAttributeModel";
@@ -7,12 +7,15 @@ import { SETTINGS_X_BINS, SETTINGS_Y_BINS, SETTINGS_SAMPLE_SIZE } from "../model
import { AttributeTransformationModel } from "../core/attribute/AttributeTransformationModel";
import { BaseOperation } from "./BaseOperation";
import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils";
+import { FilterModel } from "../core/filter/FilterModel";
export class HistogramOperation extends BaseOperation {
- public X: AttributeTransformationModel;
- public Y: AttributeTransformationModel;
- public V: AttributeTransformationModel;
+ @observable public Normalization: number = -1;
+ @observable public FilterModels: FilterModel[] = [];
+ @observable public X: AttributeTransformationModel;
+ @observable public Y: AttributeTransformationModel;
+ @observable public V: AttributeTransformationModel;
constructor(x: AttributeTransformationModel, y: AttributeTransformationModel, v: AttributeTransformationModel) {
super();
this.X = x;
diff --git a/src/client/northstar/utils/LABColor.ts b/src/client/northstar/utils/LABColor.ts
new file mode 100644
index 000000000..72e46fb7f
--- /dev/null
+++ b/src/client/northstar/utils/LABColor.ts
@@ -0,0 +1,90 @@
+
+export class LABColor {
+ public L: number;
+ public A: number;
+ public B: number;
+
+ // constructor - takes three floats for lightness and color-opponent dimensions
+ constructor(l: number, a: number, b: number) {
+ this.L = l;
+ this.A = a;
+ this.B = b;
+ }
+
+ // static function for linear interpolation between two LABColors
+ public static Lerp(a: LABColor, b: LABColor, t: number): LABColor {
+ return new LABColor(LABColor.LerpNumber(a.L, b.L, t), LABColor.LerpNumber(a.A, b.A, t), LABColor.LerpNumber(a.B, b.B, t));
+ }
+
+ public static LerpNumber(a: number, b: number, percent: number): number {
+ return a + percent * (b - a);
+ }
+
+ static hexToRGB(hex: number, alpha: number): number[] {
+ var r = (hex & (0xff << 16)) >> 16;
+ var g = (hex & (0xff << 8)) >> 8;
+ var b = (hex & (0xff << 0)) >> 0;
+ return [r, g, b];
+ }
+ static RGBtoHex(red: number, green: number, blue: number): number {
+ return blue | (green << 8) | (red << 16);
+ }
+
+ public static RGBtoHexString(rgb: number): string {
+ let str = "#" + this.hex((rgb & (0xff << 16)) >> 16) + this.hex((rgb & (0xff << 8)) >> 8) + this.hex((rgb & (0xff << 0)) >> 0);
+ return str;
+ }
+
+ static hex(x: number): string {
+ var hexDigits = new Array
+ ("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f");
+ return isNaN(x) ? "00" : hexDigits[(x - x % 16) / 16] + hexDigits[x % 16];
+ }
+
+ public static FromColor(c: number): LABColor {
+ var rgb = LABColor.hexToRGB(c, 0);
+ var r = LABColor.d3_rgb_xyz(rgb[0] * 255);
+ var g = LABColor.d3_rgb_xyz(rgb[1] * 255);
+ var b = LABColor.d3_rgb_xyz(rgb[2] * 255);
+
+ var x = LABColor.d3_xyz_lab((0.4124564 * r + 0.3575761 * g + 0.1804375 * b) / LABColor.d3_lab_X);
+ var y = LABColor.d3_xyz_lab((0.2126729 * r + 0.7151522 * g + 0.0721750 * b) / LABColor.d3_lab_Y);
+ var z = LABColor.d3_xyz_lab((0.0193339 * r + 0.1191920 * g + 0.9503041 * b) / LABColor.d3_lab_Z);
+ var lab = new LABColor(116 * y - 16, 500 * (x - y), 200 * (y - z));
+ return lab;
+ }
+
+ private static d3_lab_X: number = 0.950470;
+ private static d3_lab_Y: number = 1;
+ private static d3_lab_Z: number = 1.088830;
+
+ public static d3_lab_xyz(x: number): number {
+ return x > 0.206893034 ? x * x * x : (x - 4 / 29) / 7.787037;
+ }
+
+ public static d3_xyz_rgb(r: number): number {
+ return Math.round(255 * (r <= 0.00304 ? 12.92 * r : 1.055 * Math.pow(r, 1 / 2.4) - 0.055));
+ }
+
+ public static d3_rgb_xyz(r: number): number {
+ return (r /= 255) <= 0.04045 ? r / 12.92 : Math.pow((r + 0.055) / 1.055, 2.4);
+ }
+
+ public static d3_xyz_lab(x: number): number {
+ return x > 0.008856 ? Math.pow(x, 1 / 3) : 7.787037 * x + 4 / 29;
+ }
+
+ public static ToColor(lab: LABColor): number {
+ var y = (lab.L + 16) / 116;
+ var x = y + lab.A / 500;
+ var z = y - lab.B / 200;
+ x = LABColor.d3_lab_xyz(x) * LABColor.d3_lab_X;
+ y = LABColor.d3_lab_xyz(y) * LABColor.d3_lab_Y;
+ z = LABColor.d3_lab_xyz(z) * LABColor.d3_lab_Z;
+
+ return LABColor.RGBtoHex(
+ LABColor.d3_xyz_rgb(3.2404542 * x - 1.5371385 * y - 0.4985314 * z) / 255,
+ LABColor.d3_xyz_rgb(-0.9692660 * x + 1.8760108 * y + 0.0415560 * z) / 255,
+ LABColor.d3_xyz_rgb(0.0556434 * x - 0.2040259 * y + 1.0572252 * z) / 255);
+ }
+} \ No newline at end of file
diff --git a/src/client/northstar/utils/MathUtil.ts b/src/client/northstar/utils/MathUtil.ts
index 3ed8628ee..bb7e73871 100644
--- a/src/client/northstar/utils/MathUtil.ts
+++ b/src/client/northstar/utils/MathUtil.ts
@@ -1,13 +1,17 @@
export class PIXIPoint {
- public x: number;
- public y: number;
+ public get x() { return this.coords[0]; }
+ public get y() { return this.coords[1]; }
+ public set x(value: number) { this.coords[0] = value; }
+ public set y(value: number) { this.coords[1] = value; }
+ public coords: number[] = [0, 0];
constructor(x: number, y: number) {
- this.x = x;
- this.y = y;
+ this.coords[0] = x;
+ this.coords[1] = y;
}
}
+
export class PIXIRectangle {
public x: number;
public y: number;
@@ -17,6 +21,7 @@ export class PIXIRectangle {
public get right() { return this.x + this.width; }
public get top() { return this.y }
public get bottom() { return this.top + this.height }
+ public static get EMPTY() { return new PIXIRectangle(0, 0, -1, -1); }
constructor(x: number, y: number, width: number, height: number) {
this.x = x;
this.y = y;
diff --git a/src/client/northstar/utils/SizeConverter.ts b/src/client/northstar/utils/SizeConverter.ts
new file mode 100644
index 000000000..e8973cfd5
--- /dev/null
+++ b/src/client/northstar/utils/SizeConverter.ts
@@ -0,0 +1,80 @@
+import { PIXIPoint } from "./MathUtil";
+import { NominalVisualBinRange } from "../model/binRanges/NominalVisualBinRange";
+import { VisualBinRange } from "../model/binRanges/VisualBinRange";
+
+export class SizeConverter {
+ public RenderSize: Array<number> = new Array<number>(2);
+ public DataMins: Array<number> = new Array<number>(2);;
+ public DataMaxs: Array<number> = new Array<number>(2);;
+ public DataRanges: Array<number> = new Array<number>(2);;
+ public MaxLabelSizes: Array<PIXIPoint> = new Array<PIXIPoint>(2);;
+
+ public LeftOffset: number = 40;
+ public RightOffset: number = 20;
+ public TopOffset: number = 20;
+ public BottomOffset: number = 45;
+
+ public IsSmall: boolean = false;
+
+ constructor(size: { x: number, y: number }, visualBinRanges: Array<VisualBinRange>, labelAngle: number) {
+ this.LeftOffset = 40;
+ this.RightOffset = 20;
+ this.TopOffset = 20;
+ this.BottomOffset = 45;
+ this.IsSmall = false;
+
+ if (visualBinRanges.length < 1)
+ return;
+
+ var xLabels = visualBinRanges[0].GetLabels();
+ var yLabels = visualBinRanges[1].GetLabels();
+ var xLabelStrings = xLabels.map(l => l.label!).sort(function (a, b) { return b.length - a.length });
+ var yLabelStrings = yLabels.map(l => l.label!).sort(function (a, b) { return b.length - a.length });
+
+ var metricsX = { width: 100 }; // RenderUtils.MeasureText(FontStyles.Default.fontFamily.toString(), 12, // FontStyles.AxisLabel.fontSize as number,
+ //xLabelStrings[0]!.slice(0, 20)) // StyleConstants.MAX_CHAR_FOR_HISTOGRAM_LABELS));
+ var metricsY = { width: 22 }; // RenderUtils.MeasureText(FontStyles.Default.fontFamily.toString(), 12, // FontStyles.AxisLabel.fontSize as number,
+ // yLabelStrings[0]!.slice(0, 20)); // StyleConstants.MAX_CHAR_FOR_HISTOGRAM_LABELS));
+ this.MaxLabelSizes[0] = new PIXIPoint(metricsX.width, 12);// FontStyles.AxisLabel.fontSize as number);
+ this.MaxLabelSizes[1] = new PIXIPoint(metricsY.width, 12); // FontStyles.AxisLabel.fontSize as number);
+
+ this.LeftOffset = Math.max(10, metricsY.width + 10 + 20);
+
+ if (visualBinRanges[0] instanceof NominalVisualBinRange) {
+ var lw = this.MaxLabelSizes[0].x + 18;
+ this.BottomOffset = Math.max(this.BottomOffset, Math.cos(labelAngle) * lw) + 5;
+ this.RightOffset = Math.max(this.RightOffset, Math.sin(labelAngle) * lw);
+ }
+
+ this.RenderSize[0] = (size.x - this.LeftOffset - this.RightOffset);
+ this.RenderSize[1] = (size.y - this.TopOffset - this.BottomOffset);
+
+ //if (this.RenderSize.reduce((agg, cur) => Math.min(agg, cur), Number.MAX_VALUE) < 40) {
+ if ((this.RenderSize[0] < 40 && this.RenderSize[1] < 40) ||
+ (this.RenderSize[0] < 0 || this.RenderSize[1] < 0)) {
+ this.LeftOffset = 5;
+ this.RightOffset = 5;
+ this.TopOffset = 5;
+ this.BottomOffset = 25;
+ this.IsSmall = true;
+ this.RenderSize[0] = (size.x - this.LeftOffset - this.RightOffset);
+ this.RenderSize[1] = (size.y - this.TopOffset - this.BottomOffset);
+ }
+
+ this.DataMins[0] = xLabels.map(l => l.minValue!).reduce((m, c) => Math.min(m, c), Number.MAX_VALUE);
+ this.DataMins[1] = yLabels.map(l => l.minValue!).reduce((m, c) => Math.min(m, c), Number.MAX_VALUE);
+ this.DataMaxs[0] = xLabels.map(l => l.maxValue!).reduce((m, c) => Math.max(m, c), Number.MIN_VALUE);
+ this.DataMaxs[1] = yLabels.map(l => l.maxValue!).reduce((m, c) => Math.max(m, c), Number.MIN_VALUE);
+
+ this.DataRanges[0] = this.DataMaxs[0] - this.DataMins[0];
+ this.DataRanges[1] = this.DataMaxs[1] - this.DataMins[1];
+ }
+
+ public DataToScreenX(x: number): number {
+ return (((x - this.DataMins[0]) / this.DataRanges[0]) * (this.RenderSize[0]) + (this.LeftOffset));
+ }
+ public DataToScreenY(y: number, flip: boolean = true) {
+ var retY = ((y - this.DataMins[1]) / this.DataRanges[1]) * (this.RenderSize[1]);
+ return flip ? (this.RenderSize[1]) - retY + (this.TopOffset) : retY + (this.TopOffset);
+ }
+} \ No newline at end of file
diff --git a/src/client/northstar/utils/StyleContants.ts b/src/client/northstar/utils/StyleContants.ts
new file mode 100644
index 000000000..ac8617e3b
--- /dev/null
+++ b/src/client/northstar/utils/StyleContants.ts
@@ -0,0 +1,95 @@
+import { PIXIPoint } from "./MathUtil";
+
+export class StyleConstants {
+
+ static DEFAULT_FONT: string = "Roboto Condensed";
+
+ static MENU_SUBMENU_WIDTH: number = 85;
+ static MENU_SUBMENU_HEIGHT: number = 400;
+ static MENU_BOX_SIZE: PIXIPoint = new PIXIPoint(80, 35);
+ static MENU_BOX_PADDING: number = 10;
+
+ static OPERATOR_MENU_LARGE: number = 35;
+ static OPERATOR_MENU_SMALL: number = 25;
+ static BRUSH_PALETTE: number[] = [0x42b43c, 0xfa217f, 0x6a9c75, 0xfb5de7, 0x25b8ea, 0x9b5bc4, 0xda9f63, 0xe23209, 0xfb899b, 0x94a6fd]
+ static GAP: number = 3;
+
+ static BACKGROUND_COLOR: number = 0xF3F3F3;
+ static TOOL_TIP_BACKGROUND_COLOR: number = 0xffffff;
+ static LIGHT_TEXT_COLOR: number = 0xffffff;
+ static LIGHT_TEXT_COLOR_STR: string = StyleConstants.HexToHexString(StyleConstants.LIGHT_TEXT_COLOR);
+ static DARK_TEXT_COLOR: number = 0x282828;
+ static HIGHLIGHT_TEXT_COLOR: number = 0xffcc00;
+ static FPS_TEXT_COLOR: number = StyleConstants.DARK_TEXT_COLOR;
+ static CORRELATION_LABEL_TEXT_COLOR_STR: string = StyleConstants.HexToHexString(StyleConstants.DARK_TEXT_COLOR);
+ static LOADING_SCREEN_TEXT_COLOR_STR: string = StyleConstants.HexToHexString(StyleConstants.DARK_TEXT_COLOR);
+ static ERROR_COLOR: number = 0x540E25;
+ static WARNING_COLOR: number = 0xE58F24;
+ static LOWER_THAN_NAIVE_COLOR: number = 0xee0000;
+ static HIGHLIGHT_COLOR: number = 0x82A8D9;
+ static HIGHLIGHT_COLOR_STR: string = StyleConstants.HexToHexString(StyleConstants.HIGHLIGHT_COLOR);
+ static OPERATOR_BACKGROUND_COLOR: number = 0x282828;
+ static LOADING_ANIMATION_COLOR: number = StyleConstants.OPERATOR_BACKGROUND_COLOR;
+ static MENU_COLOR: number = 0x282828;
+ static MENU_FONT_COLOR: number = StyleConstants.LIGHT_TEXT_COLOR;
+ static MENU_SELECTED_COLOR: number = StyleConstants.HIGHLIGHT_COLOR;
+ static MENU_SELECTED_FONT_COLOR: number = StyleConstants.LIGHT_TEXT_COLOR;
+ static BRUSH_COLOR: number = 0xff0000;
+ static DROP_ACCEPT_COLOR: number = StyleConstants.HIGHLIGHT_COLOR;
+ static SELECTED_COLOR: number = 0xffffff;
+ static SELECTED_COLOR_STR: string = StyleConstants.HexToHexString(StyleConstants.SELECTED_COLOR);
+ static PROGRESS_BACKGROUND_COLOR: number = 0x595959;
+ static GRID_LINES_COLOR: number = 0x3D3D3D;
+ static GRID_LINES_COLOR_STR: string = StyleConstants.HexToHexString(StyleConstants.GRID_LINES_COLOR);
+
+ static MAX_CHAR_FOR_HISTOGRAM_LABELS: number = 20;
+
+ static OVERLAP_COLOR: number = 0x0000ff;//0x540E25;
+ static BRUSH_COLORS: Array<number> = new Array<number>(
+ 0xFFDA7E, 0xFE8F65, 0xDA5655, 0x8F2240
+ );
+
+ static MIN_VALUE_COLOR: number = 0x373d43; //32343d, 373d43, 3b4648
+ static MARGIN_BARS_COLOR: number = 0xffffff;
+ static MARGIN_BARS_COLOR_STR: string = StyleConstants.HexToHexString(StyleConstants.MARGIN_BARS_COLOR);
+
+ static HISTOGRAM_WIDTH: number = 200;
+ static HISTOGRAM_HEIGHT: number = 150;
+ static PREDICTOR_WIDTH: number = 150;
+ static PREDICTOR_HEIGHT: number = 100;
+ static RAWDATA_WIDTH: number = 150;
+ static RAWDATA_HEIGHT: number = 100;
+ static FREQUENT_ITEM_WIDTH: number = 180;
+ static FREQUENT_ITEM_HEIGHT: number = 100;
+ static CORRELATION_WIDTH: number = 555;
+ static CORRELATION_HEIGHT: number = 390;
+ static PROBLEM_FINDER_WIDTH: number = 450;
+ static PROBLEM_FINDER_HEIGHT: number = 150;
+ static PIPELINE_OPERATOR_WIDTH: number = 300;
+ static PIPELINE_OPERATOR_HEIGHT: number = 120;
+ static SLICE_WIDTH: number = 150;
+ static SLICE_HEIGHT: number = 45;
+ static BORDER_MENU_ITEM_WIDTH: number = 50;
+ static BORDER_MENU_ITEM_HEIGHT: number = 30;
+
+
+ static SLICE_BG_COLOR: string = StyleConstants.HexToHexString(StyleConstants.OPERATOR_BACKGROUND_COLOR);
+ static SLICE_EMPTY_COLOR: number = StyleConstants.OPERATOR_BACKGROUND_COLOR;
+ static SLICE_OCCUPIED_COLOR: number = 0xffffff;
+ static SLICE_OCCUPIED_BG_COLOR: string = StyleConstants.HexToHexString(StyleConstants.OPERATOR_BACKGROUND_COLOR);
+ static SLICE_HOVER_BG_COLOR: string = StyleConstants.HexToHexString(StyleConstants.HIGHLIGHT_COLOR);
+ static SLICE_HOVER_COLOR: number = 0xffffff;
+
+ static HexToHexString(hex: number): string {
+ if (hex === undefined) {
+ return "#000000";
+ }
+ var s = hex.toString(16);
+ while (s.length < 6) {
+ s = "0" + s;
+ }
+ return "#" + s;
+ }
+
+
+}
diff --git a/src/client/views/nodes/HistogramBox.scss b/src/client/views/nodes/HistogramBox.scss
index 04bf1d732..f17059f06 100644
--- a/src/client/views/nodes/HistogramBox.scss
+++ b/src/client/views/nodes/HistogramBox.scss
@@ -5,4 +5,10 @@
width: 100%;
height: 100%;
}
+ .histogrambox-xlabel {
+ position:absolute;
+ width:100%;
+ text-align: center;
+ bottom:0;
+ }
\ No newline at end of file
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
diff --git a/src/mobile/ImageUpload.tsx b/src/mobile/ImageUpload.tsx
index 47b9d8f0b..ae48dd2c6 100644
--- a/src/mobile/ImageUpload.tsx
+++ b/src/mobile/ImageUpload.tsx
@@ -1,15 +1,14 @@
import * as ReactDOM from 'react-dom';
-import React = require('react');
-import "./ImageUpload.scss"
+import * as rp from 'request-promise';
+import { Documents } from '../client/documents/Documents';
+import { Server } from '../client/Server';
import { Document } from '../fields/Document';
import { KeyStore } from '../fields/KeyStore';
-import { Server } from '../client/Server';
-import { Documents } from '../client/documents/Documents';
import { ListField } from '../fields/ListField';
-import { ImageField } from '../fields/ImageField';
-import * as rp from 'request-promise'
-import { ServerUtils } from '../server/ServerUtil';
import { RouteStore } from '../server/RouteStore';
+import { ServerUtils } from '../server/ServerUtil';
+import "./ImageUpload.scss";
+import React = require('react');