From a16e6592caafb601b59c3d9f7609e8c1af231eba Mon Sep 17 00:00:00 2001
From: bob
Date: Wed, 20 Mar 2019 18:00:39 -0400
Subject: initial
---
src/client/northstar/operations/BaseOperation.ts | 174 +++++++++++++++++++++
.../northstar/operations/HistogramOperation.ts | 111 +++++++++++++
2 files changed, 285 insertions(+)
create mode 100644 src/client/northstar/operations/BaseOperation.ts
create mode 100644 src/client/northstar/operations/HistogramOperation.ts
(limited to 'src/client/northstar/operations')
diff --git a/src/client/northstar/operations/BaseOperation.ts b/src/client/northstar/operations/BaseOperation.ts
new file mode 100644
index 000000000..4c0303a48
--- /dev/null
+++ b/src/client/northstar/operations/BaseOperation.ts
@@ -0,0 +1,174 @@
+import { FilterModel } from '../core/filter/FilterModel'
+import { ErrorResult, Exception, OperationParameters, OperationReference, Result, ResultParameters } from '../model/idea/idea';
+import { action, computed, observable } from "mobx";
+import { Gateway } from '../manager/Gateway';
+
+export abstract class BaseOperation {
+ private _interactionTimeoutId: number = 0;
+ private static _currentOperations: Map = new Map();
+ //public InteractionTimeout: EventDelegate = new EventDelegate();
+
+ @observable public Error: string = "";
+ @observable public OverridingFilters: FilterModel[] = [];
+ @observable public Result: Result | undefined;
+ @observable public ComputationStarted: boolean = false;
+ public OperationReference: OperationReference | undefined = undefined;
+
+ private static _nextId = 0;
+ public RequestSalt: string = "";
+ public Id: number;
+
+ constructor() {
+ this.Id = BaseOperation._nextId++;
+ }
+
+ @computed
+ public get FilterString(): string {
+
+ // if (this.OverridingFilters.length > 0) {
+ // return "(" + this.OverridingFilters.filter(fm => fm != null).map(fm => fm.ToPythonString()).join(" || ") + ")";
+ // }
+ // let rdg = MainManager.Instance.MainViewModel.FilterReverseDependencyGraph;
+ // let sliceModel = this.TypedViewModel.IncomingSliceModel;
+ // if (sliceModel != null && sliceModel.Source != null && instanceOfIBaseFilterProvider(sliceModel.Source) && rdg.has(sliceModel.Source)) {
+ // let filterModels = sliceModel.Source.FilterModels.map(f => f);
+ // return FilterModel.GetFilterModelsRecursive(rdg.get(sliceModel.Source), new Set>(), filterModels, false);
+ // }
+
+ // if (rdg.has(this.TypedViewModel)) {
+ // let filterModels = [];
+ // return FilterModel.GetFilterModelsRecursive(rdg.get(this.TypedViewModel), new Set>(), filterModels, true)
+ // }
+ return "";
+ }
+
+
+ @action
+ public SetResult(result: Result): void {
+ this.Result = result;
+ }
+
+ public async Update(): Promise {
+
+ try {
+ if (BaseOperation._currentOperations.has(this.Id)) {
+ BaseOperation._currentOperations.get(this.Id)!.Cancel();
+ if (this.OperationReference) {
+ Gateway.Instance.PauseOperation(this.OperationReference.toJSON());
+ }
+ }
+
+ let operationParameters = this.CreateOperationParameters();
+ this.Result = undefined;
+ this.Error = "";
+ let salt = Math.random().toString();
+ this.RequestSalt = salt;
+
+ if (!operationParameters) {
+ this.ComputationStarted = false;
+ return;
+ }
+
+ this.ComputationStarted = true;
+ //let start = performance.now();
+ let promise = Gateway.Instance.StartOperation(operationParameters.toJSON());
+ promise.catch(err => {
+ action(() => {
+ this.Error = err;
+ console.error(err);
+ });
+ });
+ let operationReference = await promise;
+
+
+ if (operationReference) {
+ this.OperationReference = operationReference;
+
+ let resultParameters = new ResultParameters();
+ resultParameters.operationReference = operationReference;
+
+ let pollPromise = new PollPromise(salt, operationReference);
+ BaseOperation._currentOperations.set(this.Id, pollPromise);
+
+ pollPromise.Start(async () => {
+ let result = await Gateway.Instance.GetResult(resultParameters.toJSON());
+ if (result instanceof ErrorResult) {
+ throw new Error((result as ErrorResult).message);
+ }
+ if (this.RequestSalt == pollPromise.RequestSalt) {
+ if (result && (!this.Result || this.Result.progress != result.progress)) {
+ /*if (operationViewModel.Result !== null && operationViewModel.Result !== undefined) {
+ let t1 = performance.now();
+ console.log((t1 - start) + " milliseconds.");
+ start = performance.now();
+ }*/
+ this.SetResult(result);
+ }
+
+ if (!result || result.progress! < 1) {
+ return true;
+ }
+ }
+ return false;
+ }, 100).catch((err: Error) => action(() => {
+ this.Error = err.message;
+ console.error(err.message);
+ })()
+ );
+ }
+ }
+ catch (err) {
+ console.error(err as Exception);
+ // ErrorDialog.Instance.HandleError(err, operationViewModel);
+ }
+ }
+
+ public CreateOperationParameters(): OperationParameters | undefined { return undefined; }
+
+ private interactionTimeout() {
+ // clearTimeout(this._interactionTimeoutId);
+ // this.InteractionTimeout.Fire(new InteractionTimeoutEventArgs(this.TypedViewModel, InteractionTimeoutType.Timeout));
+ }
+}
+
+export class PollPromise {
+ public RequestSalt: string;
+ public OperationReference: OperationReference;
+
+ private _notCanceled: boolean = true;
+ private _poll: undefined | (() => Promise);
+ private _delay: number = 0;
+
+ public constructor(requestKey: string, operationReference: OperationReference) {
+ this.RequestSalt = requestKey;
+ this.OperationReference = operationReference;
+ }
+
+ public Cancel(): void {
+ this._notCanceled = false;
+ }
+
+ public Start(poll: () => Promise, delay: number): Promise {
+ this._poll = poll;
+ this._delay = delay;
+ return this.pollRecursive();
+ }
+
+ private pollRecursive = (): Promise => {
+ return Promise.resolve().then(this._poll).then((flag) => {
+ this._notCanceled && flag && new Promise((res) => (setTimeout(res, this._delay)))
+ .then(this.pollRecursive);
+ });
+ }
+}
+
+
+export class InteractionTimeoutEventArgs {
+ constructor(public Sender: object, public Type: InteractionTimeoutType) {
+ }
+}
+
+export enum InteractionTimeoutType {
+ Reset = 0,
+ Timeout = 1
+}
diff --git a/src/client/northstar/operations/HistogramOperation.ts b/src/client/northstar/operations/HistogramOperation.ts
new file mode 100644
index 000000000..a4f5cac70
--- /dev/null
+++ b/src/client/northstar/operations/HistogramOperation.ts
@@ -0,0 +1,111 @@
+import { reaction, computed, action } 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";
+import { ModelHelpers } from "../model/ModelHelpers";
+import { SETTINGS_X_BINS, SETTINGS_Y_BINS, SETTINGS_SAMPLE_SIZE } from "../model/binRanges/VisualBinRangeHelper";
+import { AttributeTransformationModel } from "../core/attribute/AttributeTransformationModel";
+import { Main } from "../../views/Main";
+import { BaseOperation } from "./BaseOperation";
+
+
+export class HistogramOperation extends BaseOperation {
+ public X: AttributeTransformationModel;
+ public Y: AttributeTransformationModel;
+ public V: AttributeTransformationModel;
+ constructor(x: AttributeTransformationModel, y: AttributeTransformationModel, v: AttributeTransformationModel) {
+ super();
+ this.X = x;
+ this.Y = y;
+ this.V = v;
+ reaction(() => this.createOperationParamsCache, () => this.Update());
+ }
+
+ @computed.struct
+ public get BrushString() {
+ return [];
+ // let brushes = [];
+ // this.TypedViewModel.BrusherModels.map(brushLinkModel => {
+ // if (instanceOfIBaseFilterProvider(brushLinkModel.From) && brushLinkModel.From.FilterModels.some && brushLinkModel.From instanceof BaseOperationViewModel) {
+ // let brushFilterModels = [];
+ // let gnode = MainManager.Instance.MainViewModel.FilterDependencyGraph.has(brushLinkModel.From) ?
+ // MainManager.Instance.MainViewModel.FilterDependencyGraph.get(brushLinkModel.From) :
+ // new GraphNode(brushLinkModel.From);
+ // let brush = FilterModel.GetFilterModelsRecursive(gnode, new Set>(), brushFilterModels, false);
+ // brushes.push(brush);
+ // }
+ // });
+ // return brushes;
+ }
+
+
+ @computed.struct
+ public get SelectionString() {
+ return "";
+ // let filterModels = new Array();
+ // let rdg = MainManager.Instance.MainViewModel.FilterReverseDependencyGraph;
+ // let graphNode: GraphNode;
+ // if (rdg.has(this.TypedViewModel)) {
+ // graphNode = MainManager.Instance.MainViewModel.FilterReverseDependencyGraph.get(this.TypedViewModel);
+ // }
+ // else {
+ // graphNode = new GraphNode(this.TypedViewModel);
+ // }
+ // return FilterModel.GetFilterModelsRecursive(graphNode, new Set>(), filterModels, false);
+ }
+
+ GetAggregateParameters(histoX: AttributeTransformationModel, histoY: AttributeTransformationModel, histoValue: AttributeTransformationModel) {
+ let allAttributes = new Array(histoX, histoY, histoValue);
+ allAttributes = ArrayUtil.Distinct(allAttributes.filter(a => a.AggregateFunction !== AggregateFunction.None));
+
+ let numericDataTypes = [DataType.Int, DataType.Double, DataType.Float];
+ let perBinAggregateParameters: AggregateParameters[] = ModelHelpers.GetAggregateParametersWithMargins(allAttributes);
+ let globalAggregateParameters: AggregateParameters[] = [];
+ [histoX, histoY]
+ .filter(a => a.AggregateFunction === AggregateFunction.None && ArrayUtil.Contains(numericDataTypes, a.AttributeModel.DataType))
+ .forEach(a => {
+ let avg = new AverageAggregateParameters();
+ avg.attributeParameters = ModelHelpers.GetAttributeParameters(a.AttributeModel);
+ globalAggregateParameters.push(avg);
+ });
+ return [perBinAggregateParameters, globalAggregateParameters];
+ }
+
+ @computed
+ get createOperationParamsCache() {
+ return this.CreateOperationParameters();
+ }
+
+ public QRange: QuantitativeBinRange | undefined;
+
+ public CreateOperationParameters(): HistogramOperationParameters | undefined {
+ if (this.X && this.Y && this.V) {
+ let [perBinAggregateParameters, globalAggregateParameters] = this.GetAggregateParameters(this.X, this.Y, this.V);
+ return new HistogramOperationParameters({
+ enableBrushComputation: true,
+ adapterName: Main.Instance.ActiveSchema!.displayName,
+ filter: this.FilterString,
+ brushes: this.BrushString,
+ binningParameters: [ModelHelpers.GetBinningParameters(this.X, SETTINGS_X_BINS, this.QRange ? this.QRange.minValue : undefined, this.QRange ? this.QRange.maxValue : undefined),
+ ModelHelpers.GetBinningParameters(this.Y, SETTINGS_Y_BINS)],
+ sampleStreamBlockSize: SETTINGS_SAMPLE_SIZE,
+ perBinAggregateParameters: perBinAggregateParameters,
+ globalAggregateParameters: globalAggregateParameters,
+ sortPerBinAggregateParameter: undefined,
+ attributeCalculatedParameters: CalculatedAttributeManager
+ .AllCalculatedAttributes.map(a => ModelHelpers.GetAttributeParametersFromAttributeModel(a)),
+ degreeOfParallism: 1, // Settings.Instance.DegreeOfParallelism,
+ isCachable: false
+ });
+ }
+ }
+
+
+ @action
+ public async Update(): Promise {
+ // this.TypedViewModel.BrushColors = this.TypedViewModel.BrusherModels.map(e => e.Color);
+ return super.Update();
+ }
+}
+
+
--
cgit v1.2.3-70-g09d2
From dfe70d4f21a8122a6608e127203de2572a9a25fb Mon Sep 17 00:00:00 2001
From: Tyler Schicke
Date: Fri, 22 Mar 2019 05:32:20 -0400
Subject: Moved active schema out of main
---
src/client/northstar/model/ModelHelpers.ts | 10 ++++----
.../northstar/operations/HistogramOperation.ts | 4 ++--
src/client/views/Main.tsx | 21 ++---------------
src/client/views/nodes/HistogramBox.tsx | 4 ++--
.../authentication/models/current_user_utils.ts | 27 +++++++++++++++++++++-
5 files changed, 37 insertions(+), 29 deletions(-)
(limited to 'src/client/northstar/operations')
diff --git a/src/client/northstar/model/ModelHelpers.ts b/src/client/northstar/model/ModelHelpers.ts
index e1241b3ef..914e03255 100644
--- a/src/client/northstar/model/ModelHelpers.ts
+++ b/src/client/northstar/model/ModelHelpers.ts
@@ -9,7 +9,7 @@ import { AlphabeticVisualBinRange } from "./binRanges/AlphabeticVisualBinRange";
import { NominalVisualBinRange } from "./binRanges/NominalVisualBinRange";
import { VisualBinRangeHelper } from "./binRanges/VisualBinRangeHelper";
import { AttributeTransformationModel } from "../core/attribute/AttributeTransformationModel";
-import { Main } from "../../views/Main";
+import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils";
export class ModelHelpers {
@@ -39,19 +39,19 @@ export class ModelHelpers {
if (atm.AggregateFunction === AggregateFunction.Avg) {
var avg = new AverageAggregateParameters();
avg.attributeParameters = ModelHelpers.GetAttributeParameters(atm.AttributeModel);
- avg.distinctAttributeParameters = Main.Instance.ActiveSchema!.distinctAttributeParameters;
+ avg.distinctAttributeParameters = CurrentUserUtils.ActiveSchema!.distinctAttributeParameters;
aggParam = avg;
}
else if (atm.AggregateFunction === AggregateFunction.Count) {
var cnt = new CountAggregateParameters();
cnt.attributeParameters = ModelHelpers.GetAttributeParameters(atm.AttributeModel);
- cnt.distinctAttributeParameters = Main.Instance.ActiveSchema!.distinctAttributeParameters;
+ cnt.distinctAttributeParameters = CurrentUserUtils.ActiveSchema!.distinctAttributeParameters;
aggParam = cnt;
}
else if (atm.AggregateFunction === AggregateFunction.Sum) {
var sum = new SumAggregateParameters();
sum.attributeParameters = ModelHelpers.GetAttributeParameters(atm.AttributeModel);
- sum.distinctAttributeParameters = Main.Instance.ActiveSchema!.distinctAttributeParameters;
+ sum.distinctAttributeParameters = CurrentUserUtils.ActiveSchema!.distinctAttributeParameters;
aggParam = sum;
}
return aggParam;
@@ -66,7 +66,7 @@ export class ModelHelpers {
var margin = new MarginAggregateParameters();
margin.attributeParameters = ModelHelpers.GetAttributeParameters(agg.AttributeModel);
- margin.distinctAttributeParameters = Main.Instance.ActiveSchema!.distinctAttributeParameters;
+ margin.distinctAttributeParameters = CurrentUserUtils.ActiveSchema!.distinctAttributeParameters;
margin.aggregateFunction = agg.AggregateFunction;
aggregateParameters.push(margin);
}
diff --git a/src/client/northstar/operations/HistogramOperation.ts b/src/client/northstar/operations/HistogramOperation.ts
index a4f5cac70..120a84dad 100644
--- a/src/client/northstar/operations/HistogramOperation.ts
+++ b/src/client/northstar/operations/HistogramOperation.ts
@@ -5,8 +5,8 @@ import { CalculatedAttributeManager } from "../core/attribute/CalculatedAttribut
import { ModelHelpers } from "../model/ModelHelpers";
import { SETTINGS_X_BINS, SETTINGS_Y_BINS, SETTINGS_SAMPLE_SIZE } from "../model/binRanges/VisualBinRangeHelper";
import { AttributeTransformationModel } from "../core/attribute/AttributeTransformationModel";
-import { Main } from "../../views/Main";
import { BaseOperation } from "./BaseOperation";
+import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils";
export class HistogramOperation extends BaseOperation {
@@ -83,7 +83,7 @@ export class HistogramOperation extends BaseOperation {
let [perBinAggregateParameters, globalAggregateParameters] = this.GetAggregateParameters(this.X, this.Y, this.V);
return new HistogramOperationParameters({
enableBrushComputation: true,
- adapterName: Main.Instance.ActiveSchema!.displayName,
+ adapterName: CurrentUserUtils.ActiveSchema!.displayName,
filter: this.FilterString,
brushes: this.BrushString,
binningParameters: [ModelHelpers.GetBinningParameters(this.X, SETTINGS_X_BINS, this.QRange ? this.QRange.minValue : undefined, this.QRange ? this.QRange.maxValue : undefined),
diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx
index cb49bc4e6..6534cb4f7 100644
--- a/src/client/views/Main.tsx
+++ b/src/client/views/Main.tsx
@@ -55,7 +55,6 @@ export class Main extends React.Component {
@observable private mainfreeform?: Document;
@observable public pwidth: number = 0;
@observable public pheight: number = 0;
- @observable ActiveSchema: Schema | undefined;
private _northstarColumns: Document[] = [];
@computed private get mainContainer(): Document | undefined {
@@ -339,8 +338,8 @@ export class Main extends React.Component {
@action SetNorthstarCatalog(ctlog: Catalog) {
if (ctlog && ctlog.schemas) {
- this.ActiveSchema = ArrayUtil.FirstOrDefault(ctlog.schemas!, (s: Schema) => s.displayName === "mimic");
- this._northstarColumns = this.GetAllNorthstarColumnAttributes().map(a => Documents.HistogramDocument({ width: 200, height: 200, title: a.displayName! }));
+ CurrentUserUtils.ActiveSchema = ArrayUtil.FirstOrDefault(ctlog.schemas!, (s: Schema) => s.displayName === "mimic");
+ this._northstarColumns = CurrentUserUtils.GetAllNorthstarColumnAttributes().map(a => Documents.HistogramDocument({ width: 200, height: 200, title: a.displayName! }));
}
}
async initializeNorthstar(): Promise {
@@ -355,22 +354,6 @@ export class Main extends React.Component {
let cat = Gateway.Instance.ClearCatalog();
cat.then(async () => this.SetNorthstarCatalog(await Gateway.Instance.GetCatalog()));
}
- public GetAllNorthstarColumnAttributes() {
- if (!this.ActiveSchema || !this.ActiveSchema.rootAttributeGroup) {
- return [];
- }
- const recurs = (attrs: Attribute[], g: AttributeGroup) => {
- if (g.attributes) {
- attrs.push.apply(attrs, g.attributes);
- if (g.attributeGroups) {
- g.attributeGroups.forEach(ng => recurs(attrs, ng));
- }
- }
- };
- const allAttributes: Attribute[] = new Array();
- recurs(allAttributes, this.ActiveSchema.rootAttributeGroup);
- return allAttributes;
- }
}
Documents.initProtos().then(() => {
diff --git a/src/client/views/nodes/HistogramBox.tsx b/src/client/views/nodes/HistogramBox.tsx
index 223fdf0d8..cc43899c1 100644
--- a/src/client/views/nodes/HistogramBox.tsx
+++ b/src/client/views/nodes/HistogramBox.tsx
@@ -4,11 +4,11 @@ import { FieldView, FieldViewProps } from './FieldView';
import "./VideoBox.scss";
import { observable, reaction } from "mobx";
import { HistogramOperation } from "../../northstar/operations/HistogramOperation";
-import { Main } from "../Main";
import { ColumnAttributeModel } from "../../northstar/core/attribute/AttributeModel";
import { AttributeTransformationModel } from "../../northstar/core/attribute/AttributeTransformationModel";
import { AggregateFunction, HistogramResult, DoubleValueAggregateResult } from "../../northstar/model/idea/idea";
import { ModelHelpers } from "../../northstar/model/ModelHelpers";
+import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils";
@observer
export class HistogramBox extends React.Component {
@@ -23,7 +23,7 @@ export class HistogramBox extends React.Component {
_histoOp?: HistogramOperation;
componentDidMount() {
- Main.Instance.GetAllNorthstarColumnAttributes().map(a => {
+ 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),
diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts
index 3291c671c..055e4cc97 100644
--- a/src/server/authentication/models/current_user_utils.ts
+++ b/src/server/authentication/models/current_user_utils.ts
@@ -7,13 +7,15 @@ import { Document } from "../../../fields/Document";
import { KeyStore } from "../../../fields/KeyStore";
import { ListField } from "../../../fields/ListField";
import { Documents } from "../../../client/documents/Documents";
+import { Schema, Attribute, AttributeGroup } from "../../../client/northstar/model/idea/idea";
export class CurrentUserUtils {
private static curr_email: string;
private static curr_id: string;
private static user_document: Document;
- //TODO tfs: this should be temporary...
+ //TODO tfs: these should be temporary...
private static mainDocId: string | undefined;
+ private static activeSchema: Schema | undefined;
public static get email(): string {
return this.curr_email;
@@ -35,6 +37,29 @@ export class CurrentUserUtils {
this.mainDocId = id;
}
+ public static get ActiveSchema(): Schema | undefined {
+ return this.activeSchema;
+ }
+ public static GetAllNorthstarColumnAttributes() {
+ if (!this.ActiveSchema || !this.ActiveSchema.rootAttributeGroup) {
+ return [];
+ }
+ const recurs = (attrs: Attribute[], g: AttributeGroup) => {
+ if (g.attributes) {
+ attrs.push.apply(attrs, g.attributes);
+ if (g.attributeGroups) {
+ g.attributeGroups.forEach(ng => recurs(attrs, ng));
+ }
+ }
+ };
+ const allAttributes: Attribute[] = new Array();
+ recurs(allAttributes, this.ActiveSchema.rootAttributeGroup);
+ return allAttributes;
+ }
+
+ public static set ActiveSchema(id: Schema | undefined) {
+ this.activeSchema = id;
+ }
private static createUserDocument(id: string): Document {
let doc = new Document(id);
--
cgit v1.2.3-70-g09d2
From 60ff3da65fbabd21c29bf1eecace02ebc1f6430c Mon Sep 17 00:00:00 2001
From: bob
Date: Mon, 25 Mar 2019 16:00:59 -0400
Subject: histograms render
---
.../northstar/operations/HistogramOperation.ts | 11 +-
src/client/northstar/utils/LABColor.ts | 90 ++++
src/client/northstar/utils/MathUtil.ts | 13 +-
src/client/northstar/utils/SizeConverter.ts | 80 +++
src/client/northstar/utils/StyleContants.ts | 95 ++++
src/client/views/nodes/HistogramBox.scss | 6 +
src/client/views/nodes/HistogramBox.tsx | 540 +++++++++++++++++++--
7 files changed, 788 insertions(+), 47 deletions(-)
create mode 100644 src/client/northstar/utils/LABColor.ts
create mode 100644 src/client/northstar/utils/SizeConverter.ts
create mode 100644 src/client/northstar/utils/StyleContants.ts
(limited to 'src/client/northstar/operations')
diff --git a/src/client/northstar/operations/HistogramOperation.ts b/src/client/northstar/operations/HistogramOperation.ts
index a4f5cac70..5ee1c0795 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 { Main } from "../../views/Main";
import { BaseOperation } from "./BaseOperation";
+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 = new Array(2);
+ public DataMins: Array = new Array(2);;
+ public DataMaxs: Array = new Array(2);;
+ public DataRanges: Array = new Array(2);;
+ public MaxLabelSizes: Array = new Array(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, 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 = new Array(
+ 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 223fdf0d8..980719a21 100644
--- a/src/client/views/nodes/HistogramBox.tsx
+++ b/src/client/views/nodes/HistogramBox.tsx
@@ -1,67 +1,529 @@
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 { Main } from "../Main";
+import Measure from "react-measure";
+import { Dictionary } from "typescript-collections";
+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 { DateTimeVisualBinRange } from "../../northstar/model/binRanges/DateTimeVisualBinRange";
+import { NominalVisualBinRange } from "../../northstar/model/binRanges/NominalVisualBinRange";
+import { QuantitativeVisualBinRange } from "../../northstar/model/binRanges/QuantitativeVisualBinRange";
+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 { 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 { Main } from "../Main";
+import { FieldView, FieldViewProps } from './FieldView';
+import "./HistogramBox.scss";
+
+
@observer
export class HistogramBox extends React.Component {
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 = new Dictionary();
+
+
+
constructor(props: FieldViewProps) {
super(props);
}
- @observable _histoResult?: HistogramResult;
- _histoOp?: HistogramOperation;
-
componentDidMount() {
- Main.Instance.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],
+ () => {
+ Main.Instance.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 ;
+ }
+
+ 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))); // (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(
+
+ {text}
+
)
+ }
+ }
+ 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();
+ 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
}
render() {
- if (!this._histoResult)
+ if (!this.binPrimitives || !this._histoOp || !(this._histoOp.Result instanceof HistogramResult) || !this._visualBinRanges.length) {
return (null);
+ }
+
return (
-
- `HISTOGRAM RESULT : ${this.twoString()}`
-
+
+ {({ measureRef }) =>
+
+ {this.xaxislines}
+ {this.yaxislines}
+ {this.binPrimitives}
+
{this._histoOp!.X.AttributeModel.DisplayName}
+
+ }
+
)
}
+}
+
+export class HistogramBinPrimitive {
+ constructor(init?: Partial) {
+ 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 = new Array();
+ 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;
+
+ constructor(bin: Bin, histoResult: HistogramResult,
+ value: AttributeTransformationModel, x: AttributeTransformationModel, y: AttributeTransformationModel,
+ chartType: ChartType, visualBinRanges: Array,
+ 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();
+ 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, 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
--
cgit v1.2.3-70-g09d2
From 731cab330389b1730d9700b5452ac75975b79b3c Mon Sep 17 00:00:00 2001
From: bob
Date: Tue, 26 Mar 2019 09:28:35 -0400
Subject: minor restructure
---
src/client/northstar/model/ModelHelpers.ts | 4 +-
.../northstar/operations/HistogramOperation.ts | 7 ++-
src/client/views/nodes/HistogramBox.tsx | 64 +++++++++-------------
3 files changed, 33 insertions(+), 42 deletions(-)
(limited to 'src/client/northstar/operations')
diff --git a/src/client/northstar/model/ModelHelpers.ts b/src/client/northstar/model/ModelHelpers.ts
index 914e03255..8de0bd260 100644
--- a/src/client/northstar/model/ModelHelpers.ts
+++ b/src/client/northstar/model/ModelHelpers.ts
@@ -64,10 +64,10 @@ export class ModelHelpers {
if (aggParams) {
aggregateParameters.push(aggParams);
- var margin = new MarginAggregateParameters();
+ var margin = new MarginAggregateParameters()
+ margin.aggregateFunction = agg.AggregateFunction;
margin.attributeParameters = ModelHelpers.GetAttributeParameters(agg.AttributeModel);
margin.distinctAttributeParameters = CurrentUserUtils.ActiveSchema!.distinctAttributeParameters;
- margin.aggregateFunction = agg.AggregateFunction;
aggregateParameters.push(margin);
}
});
diff --git a/src/client/northstar/operations/HistogramOperation.ts b/src/client/northstar/operations/HistogramOperation.ts
index 8367cc725..cf2571285 100644
--- a/src/client/northstar/operations/HistogramOperation.ts
+++ b/src/client/northstar/operations/HistogramOperation.ts
@@ -8,14 +8,19 @@ import { AttributeTransformationModel } from "../core/attribute/AttributeTransfo
import { BaseOperation } from "./BaseOperation";
import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils";
import { FilterModel } from "../core/filter/FilterModel";
+import { BrushLinkModel } from "../core/brusher/BrushLinkModel";
export class HistogramOperation extends BaseOperation {
+ @observable public BrushColors: number[] = [];
@observable public Normalization: number = -1;
@observable public FilterModels: FilterModel[] = [];
@observable public X: AttributeTransformationModel;
@observable public Y: AttributeTransformationModel;
@observable public V: AttributeTransformationModel;
+ @observable public BrusherModels: BrushLinkModel[] = [];
+ @observable public BrushableModels: BrushLinkModel[] = [];
+
constructor(x: AttributeTransformationModel, y: AttributeTransformationModel, v: AttributeTransformationModel) {
super();
this.X = x;
@@ -106,7 +111,7 @@ export class HistogramOperation extends BaseOperation {
@action
public async Update(): Promise {
- // this.TypedViewModel.BrushColors = this.TypedViewModel.BrusherModels.map(e => e.Color);
+ this.BrushColors = this.BrusherModels.map(e => e.Color);
return super.Update();
}
}
diff --git a/src/client/views/nodes/HistogramBox.tsx b/src/client/views/nodes/HistogramBox.tsx
index c6903d397..675bf30b2 100644
--- a/src/client/views/nodes/HistogramBox.tsx
+++ b/src/client/views/nodes/HistogramBox.tsx
@@ -154,15 +154,18 @@ export class HistogramBox extends React.Component {
if (this.HistoOp.Result.bins.hasOwnProperty(key)) {
let drawPrims = new HistogramBinPrimitiveCollection(key, this);
- this.HitTargets.setValue(drawPrims.HitGeom, drawPrims.FilterModel);
+ let filterModel = ModelHelpers.GetBinFilterModel(this.HistoOp.Result.bins![key], allBrushIndex, this.HistoOp.Result, this.HistoOp.X, this.HistoOp.Y);
- if (ArrayUtil.Contains(this.HistoOp.FilterModels, drawPrims.FilterModel)) {
+
+ 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 => {
- prims.push(this.drawRect(binPrimitive.Rect, binPrimitive.Color, () => { console.log("FM = " + drawPrims.FilterModel.ToPythonString()) }));
- prims.push(this.drawRect(binPrimitive.MarginRect, StyleConstants.MARGIN_BARS_COLOR, () => { console.log("FM = " + drawPrims.FilterModel.ToPythonString()) }));
+ prims.push(this.drawRect(binPrimitive.Rect, binPrimitive.Color, () => { console.log("FM = " + filterModel.ToPythonString()) }));
+ prims.push(this.drawRect(binPrimitive.MarginRect, StyleConstants.MARGIN_BARS_COLOR, () => { console.log("FM = " + filterModel.ToPythonString()) }));
});
}
}
@@ -205,21 +208,17 @@ export class HistogramBinPrimitive {
export class HistogramBinPrimitiveCollection {
private static TOLERANCE: number = 0.0001;
- public BinPrimitives: Array = new Array();
- public FilterModel: FilterModel;
- public HitGeom: PIXIRectangle = PIXIRectangle.EMPTY;
private _histoBox: HistogramBox;
private get histoOp() { return this._histoBox.HistoOp!; }
private get histoResult() { return this.histoOp.Result as HistogramResult; }
+ public BinPrimitives: Array = new Array();
+ public HitGeom: PIXIRectangle = PIXIRectangle.EMPTY;
constructor(key: string, histoBox: HistogramBox) {
this._histoBox = histoBox;
let bin = this.histoResult.bins![key];
- var allBrushIndex = ModelHelpers.AllBrushIndex(this.histoResult);
var overlapBrushIndex = ModelHelpers.OverlapBrushIndex(this.histoResult);
- this.FilterModel = ModelHelpers.GetBinFilterModel(bin, allBrushIndex, this.histoResult, this.histoOp.X, this.histoOp.Y);
-
var orderedBrushes = new Array();
orderedBrushes.push(this.histoResult.brushes![0]);
orderedBrushes.push(this.histoResult.brushes![overlapBrushIndex]);
@@ -257,6 +256,7 @@ export class HistogramBinPrimitiveCollection {
// 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 => {
@@ -304,23 +304,19 @@ export class HistogramBinPrimitiveCollection {
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.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]);
- xFrom = sizeConverter.DataToScreenX(tx);
- xTo = sizeConverter.DataToScreenX(this._histoBox.VisualBinRanges[0].AddStep(tx));
+ 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]);
- yFrom = sizeConverter.DataToScreenY(ty);
- yTo = sizeConverter.DataToScreenY(this._histoBox.VisualBinRanges[1].AddStep(ty));
+ 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;
@@ -344,23 +340,13 @@ export class HistogramBinPrimitiveCollection {
(alpha + Math.pow(normalizedValue, 1.0 / 3.0) * (1.0 - alpha)));
var dataColor = LABColor.ToColor(lerpColor);
- var marginParams = new MarginAggregateParameters();
- marginParams.aggregateFunction = this.histoOp.V.AggregateFunction;
- var marginAggregateKey = ModelHelpers.CreateAggregateKey(this.histoOp.V, 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.histoOp.Y, this.histoResult, brush.brushIndex!);
- var marginParams = new MarginAggregateParameters();
- marginParams.aggregateFunction = this.histoOp.Y.AggregateFunction;
-
var xAggregateKey = ModelHelpers.CreateAggregateKey(this.histoOp.X, this.histoResult, brush.brushIndex!);
- var marginParams = new MarginAggregateParameters();
- marginParams.aggregateFunction = this.histoOp.X.AggregateFunction;
var xValue = ModelHelpers.GetAggregateResult(bin, xAggregateKey) as DoubleValueAggregateResult;
if (!xValue.hasResult)
@@ -395,8 +381,8 @@ export class HistogramBinPrimitiveCollection {
var xFrom = sizeConverter.DataToScreenX(xValue);
var xTo = sizeConverter.DataToScreenX(this._histoBox.VisualBinRanges[0].AddStep(xValue));
- var marginResult = ModelHelpers.GetAggregateResult(bin, yMarginAggregateKey)!;
- var yMarginAbsolute = marginResult == null ? 0 : (marginResult as MarginAggregateResult).absolutMargin!;
+ 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));
@@ -423,8 +409,8 @@ export class HistogramBinPrimitiveCollection {
var yFrom = yValue;
var yTo = this._histoBox.VisualBinRanges[1].AddStep(yValue);
- var marginResult = ModelHelpers.GetAggregateResult(bin, xMarginAggregateKey);
- var xMarginAbsolute = sizeConverter.IsSmall || marginResult == null ? 0 : (marginResult as MarginAggregateResult).absolutMargin!;
+ 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,
@@ -469,12 +455,12 @@ export class HistogramBinPrimitiveCollection {
baseColor = 0x00ff00;
}
else {
- // if (this._histogramOperationViewModel.BrushColors.length > 0) {
- // baseColor = this._histogramOperationViewModel.BrushColors[brush.brushIndex! % this._histogramOperationViewModel.BrushColors.length];
- // }
- // else {
- baseColor = StyleConstants.HIGHLIGHT_COLOR;
- // }
+ 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;
}
--
cgit v1.2.3-70-g09d2
From 8335f0ba0b780a0ed0619e52076f051f122e4865 Mon Sep 17 00:00:00 2001
From: bob
Date: Tue, 26 Mar 2019 12:37:26 -0400
Subject: added HistogramField
---
package.json | 1 +
src/client/documents/Documents.ts | 9 ++--
src/client/northstar/core/filter/FilterModel.ts | 21 ++++----
.../northstar/core/filter/IBaseFilterConsumer.ts | 2 +
.../northstar/operations/HistogramOperation.ts | 42 ++++++++-------
src/client/views/Main.tsx | 22 +++++++-
src/client/views/nodes/HistogramBox.tsx | 60 ++++++++++++++--------
src/fields/HistogramField.ts | 59 +++++++++++++++++++++
src/fields/KeyStore.ts | 2 +-
src/server/Message.ts | 2 +-
src/server/ServerUtil.ts | 3 ++
.../authentication/models/current_user_utils.ts | 3 ++
12 files changed, 166 insertions(+), 60 deletions(-)
create mode 100644 src/fields/HistogramField.ts
(limited to 'src/client/northstar/operations')
diff --git a/package.json b/package.json
index 4f75d139d..27b3eead1 100644
--- a/package.json
+++ b/package.json
@@ -92,6 +92,7 @@
"bluebird": "^3.5.3",
"body-parser": "^1.18.3",
"bootstrap": "^4.3.1",
+ "class-transformer": "^0.2.0",
"connect-flash": "^0.1.1",
"connect-mongo": "^2.0.3",
"cookie-parser": "^1.4.4",
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index bc0a18d50..1d23b8c2c 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -24,6 +24,8 @@ import { VideoBox } from "../views/nodes/VideoBox";
import { WebBox } from "../views/nodes/WebBox";
import { HistogramBox } from "../views/nodes/HistogramBox";
import { FieldView } from "../views/nodes/FieldView";
+import { HistogramField } from "../../fields/HistogramField";
+import { HistogramOperation } from "../northstar/operations/HistogramOperation";
export interface DocumentOptions {
x?: number;
@@ -42,6 +44,7 @@ export interface DocumentOptions {
layoutKeys?: Key[];
viewType?: number;
backgroundColor?: string;
+ northstarSchema?: string;
}
export namespace Documents {
@@ -85,6 +88,7 @@ export namespace Documents {
if (options.ink !== undefined) { doc.Set(KeyStore.Ink, new InkField(options.ink)); }
if (options.layout !== undefined) { doc.SetText(KeyStore.Layout, options.layout); }
if (options.layoutKeys !== undefined) { doc.Set(KeyStore.LayoutKeys, new ListField(options.layoutKeys)); }
+ if (options.northstarSchema !== undefined) { doc.SetText(KeyStore.NorthstarSchema, options.northstarSchema); }
return doc;
}
@@ -120,7 +124,6 @@ export namespace Documents {
}
function GetHistogramPrototype(): Document {
if (!histoProto) {
-
histoProto = setupPrototypeOptions(histoProtoId, "HISTO PROTO", CollectionView.LayoutString("AnnotationsKey"),
{ x: 0, y: 0, width: 300, height: 300, layoutKeys: [KeyStore.Data, KeyStore.Annotations, KeyStore.Caption] });
histoProto.SetText(KeyStore.BackgroundLayout, HistogramBox.LayoutString());
@@ -189,8 +192,8 @@ export namespace Documents {
return assignToDelegate(SetInstanceOptions(GetAudioPrototype(), options, [new URL(url), AudioField]), options);
}
- export function HistogramDocument(options: DocumentOptions = {}) {
- return assignToDelegate(SetInstanceOptions(GetHistogramPrototype(), options, ["", TextField]).MakeDelegate(), options);
+ export function HistogramDocument(histoOp: HistogramOperation, options: DocumentOptions = {}, id?: string) {
+ return assignToDelegate(SetInstanceOptions(GetHistogramPrototype(), options, [histoOp, HistogramField], id).MakeDelegate(), options);
}
export function TextDocument(options: DocumentOptions = {}) {
return assignToDelegate(SetInstanceOptions(GetTextPrototype(), options, ["", TextField]).MakeDelegate(), options);
diff --git a/src/client/northstar/core/filter/FilterModel.ts b/src/client/northstar/core/filter/FilterModel.ts
index 3c4cfc4a7..01bf2a809 100644
--- a/src/client/northstar/core/filter/FilterModel.ts
+++ b/src/client/northstar/core/filter/FilterModel.ts
@@ -1,5 +1,8 @@
import { ValueComparison } from "./ValueComparision";
import { Utils } from "../../utils/Utils";
+import { IBaseFilterProvider } from "./IBaseFilterProvider";
+import { BaseOperation } from "../../operations/BaseOperation";
+import { FilterOperand } from "./FilterOperand";
export class FilterModel {
public ValueComparisons: ValueComparison[];
@@ -36,20 +39,20 @@ export class FilterModel {
return ret;
}
- // public static GetFilterModelsRecursive(filterGraphNode: GraphNode,
- // visitedFilterProviders: Set>, filterModels: FilterModel[], isFirst: boolean): string {
+ // public static GetFilterModelsRecursive(baseOperation: BaseOperation,
+ // visitedFilterProviders: Set, filterModels: FilterModel[], isFirst: boolean): string {
// let ret = "";
- // if (Utils.isBaseFilterProvider(filterGraphNode.Data)) {
- // visitedFilterProviders.add(filterGraphNode);
- // let filtered = filterGraphNode.Data.FilterModels.filter(fm => fm && fm.ValueComparisons.length > 0);
+ // 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 = "(" + filterGraphNode.Data.FilterModels.filter(fm => fm != null).map(fm => fm.ToPythonString()).join(" || ") + ")";
+ // ret = "(" + baseOperation.FilterModels.filter(fm => fm != null).map(fm => fm.ToPythonString()).join(" || ") + ")";
// }
// }
- // if (Utils.isBaseFilterConsumer(filterGraphNode.Data) && filterGraphNode.Links != null) {
+ // if (Utils.isBaseFilterConsumer(baseOperation) && baseOperation.Links) {
// let children = new Array();
- // let linkedGraphNodes = filterGraphNode.Links.get(LinkType.Filter);
+ // let linkedGraphNodes = baseOperation.Links.get(LinkType.Filter);
// if (linkedGraphNodes != null) {
// for (let i = 0; i < linkedGraphNodes.length; i++) {
// let linkVm = linkedGraphNodes[i].Data;
@@ -66,7 +69,7 @@ export class FilterModel {
// }
// }
- // let childrenJoined = children.join(filterGraphNode.Data.FilterOperand === FilterOperand.AND ? " && " : " || ");
+ // let childrenJoined = children.join(baseOperation.FilterOperand === FilterOperand.AND ? " && " : " || ");
// if (children.length > 0) {
// if (ret !== "") {
// ret = "(" + ret + " && (" + childrenJoined + "))";
diff --git a/src/client/northstar/core/filter/IBaseFilterConsumer.ts b/src/client/northstar/core/filter/IBaseFilterConsumer.ts
index e687acb8a..3eb32b6db 100644
--- a/src/client/northstar/core/filter/IBaseFilterConsumer.ts
+++ b/src/client/northstar/core/filter/IBaseFilterConsumer.ts
@@ -1,8 +1,10 @@
import { FilterOperand } from '../filter/FilterOperand'
import { IEquatable } from '../../utils/IEquatable'
+import { IBaseFilterProvider } from './IBaseFilterProvider';
export interface IBaseFilterConsumer extends IEquatable {
FilterOperand: FilterOperand;
+ Links: IBaseFilterProvider[];
}
export function instanceOfIBaseFilterConsumer(object: any): object is IBaseFilterConsumer {
diff --git a/src/client/northstar/operations/HistogramOperation.ts b/src/client/northstar/operations/HistogramOperation.ts
index cf2571285..0c38679e5 100644
--- a/src/client/northstar/operations/HistogramOperation.ts
+++ b/src/client/northstar/operations/HistogramOperation.ts
@@ -9,9 +9,15 @@ import { BaseOperation } from "./BaseOperation";
import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils";
import { FilterModel } from "../core/filter/FilterModel";
import { BrushLinkModel } from "../core/brusher/BrushLinkModel";
+import { IBaseFilterConsumer } from "../core/filter/IBaseFilterConsumer";
+import { FilterOperand } from "../core/filter/FilterOperand";
+import { IBaseFilterProvider } from "../core/filter/IBaseFilterProvider";
+import { AttributeModel, ColumnAttributeModel } from "../core/attribute/AttributeModel";
-export class HistogramOperation extends BaseOperation {
+export class HistogramOperation extends BaseOperation implements IBaseFilterConsumer, IBaseFilterProvider {
+ @observable public FilterOperand: FilterOperand = FilterOperand.AND;
+ @observable public Links: IBaseFilterProvider[] = [];
@observable public BrushColors: number[] = [];
@observable public Normalization: number = -1;
@observable public FilterModels: FilterModel[] = [];
@@ -21,12 +27,18 @@ export class HistogramOperation extends BaseOperation {
@observable public BrusherModels: BrushLinkModel[] = [];
@observable public BrushableModels: BrushLinkModel[] = [];
- constructor(x: AttributeTransformationModel, y: AttributeTransformationModel, v: AttributeTransformationModel) {
+ public static Empty = new HistogramOperation(new AttributeTransformationModel(new ColumnAttributeModel(new Attribute())), new AttributeTransformationModel(new ColumnAttributeModel(new Attribute())), new AttributeTransformationModel(new ColumnAttributeModel(new Attribute())));
+
+ Equals(other: Object): boolean {
+ throw new Error("Method not implemented.");
+ }
+
+ constructor(x: AttributeTransformationModel, y: AttributeTransformationModel, v: AttributeTransformationModel, normalized?: number) {
super();
this.X = x;
this.Y = y;
this.V = v;
- reaction(() => this.createOperationParamsCache, () => this.Update());
+ this.Normalization = normalized ? normalized : -1;
}
@computed.struct
@@ -47,20 +59,11 @@ export class HistogramOperation extends BaseOperation {
}
- @computed.struct
- public get SelectionString() {
- return "";
- // let filterModels = new Array();
- // let rdg = MainManager.Instance.MainViewModel.FilterReverseDependencyGraph;
- // let graphNode: GraphNode;
- // if (rdg.has(this.TypedViewModel)) {
- // graphNode = MainManager.Instance.MainViewModel.FilterReverseDependencyGraph.get(this.TypedViewModel);
- // }
- // else {
- // graphNode = new GraphNode(this.TypedViewModel);
- // }
- // return FilterModel.GetFilterModelsRecursive(graphNode, new Set>(), filterModels, false);
- }
+ // @computed.struct
+ // public get SelectionString() {
+ // let filterModels = new Array();
+ // return FilterModel.GetFilterModelsRecursive(this, new Set>(), filterModels, false);
+ // }
GetAggregateParameters(histoX: AttributeTransformationModel, histoY: AttributeTransformationModel, histoValue: AttributeTransformationModel) {
let allAttributes = new Array(histoX, histoY, histoValue);
@@ -79,11 +82,6 @@ export class HistogramOperation extends BaseOperation {
return [perBinAggregateParameters, globalAggregateParameters];
}
- @computed
- get createOperationParamsCache() {
- return this.CreateOperationParameters();
- }
-
public QRange: QuantitativeBinRange | undefined;
public CreateOperationParameters(): HistogramOperationParameters | undefined {
diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx
index 6534cb4f7..3e0e02f42 100644
--- a/src/client/views/Main.tsx
+++ b/src/client/views/Main.tsx
@@ -44,10 +44,13 @@ import { CurrentUserUtils } from '../../server/authentication/models/current_use
import { Field, Opt, FieldWaiting } from '../../fields/Field';
import { ListField } from '../../fields/ListField';
import { Gateway, Settings } from '../northstar/manager/Gateway';
-import { Catalog, Schema, Attribute, AttributeGroup } from '../northstar/model/idea/idea';
+import { Catalog, Schema, Attribute, AttributeGroup, AggregateFunction } from '../northstar/model/idea/idea';
import { ArrayUtil } from '../northstar/utils/ArrayUtil';
import '../northstar/model/ModelExtensions'
import '../northstar/utils/Extensions'
+import { HistogramOperation } from '../northstar/operations/HistogramOperation';
+import { AttributeTransformationModel } from '../northstar/core/attribute/AttributeTransformationModel';
+import { ColumnAttributeModel } from '../northstar/core/attribute/AttributeModel';
@observer
export class Main extends React.Component {
@@ -339,7 +342,22 @@ export class Main extends React.Component {
@action SetNorthstarCatalog(ctlog: Catalog) {
if (ctlog && ctlog.schemas) {
CurrentUserUtils.ActiveSchema = ArrayUtil.FirstOrDefault(ctlog.schemas!, (s: Schema) => s.displayName === "mimic");
- this._northstarColumns = CurrentUserUtils.GetAllNorthstarColumnAttributes().map(a => Documents.HistogramDocument({ width: 200, height: 200, title: a.displayName! }));
+ CurrentUserUtils.GetAllNorthstarColumnAttributes().map(attr => {
+ Server.GetField(attr.displayName!, action((field: Opt) => {
+ if (field instanceof Document) {
+ this._northstarColumns.push(field);
+ } else {
+ var atmod = new ColumnAttributeModel(attr);
+ let histoOp = new HistogramOperation(
+ new AttributeTransformationModel(atmod, AggregateFunction.None),
+ new AttributeTransformationModel(atmod, AggregateFunction.Count),
+ new AttributeTransformationModel(atmod, AggregateFunction.Count));
+ this._northstarColumns.push(Documents.HistogramDocument(histoOp, { width: 200, height: 200, title: attr.displayName!, northstarSchema: CurrentUserUtils.ActiveSchema!.displayName! }, attr.displayName!));
+ }
+ }));
+ })
+ console.log("Activating schema " + CurrentUserUtils.ActiveSchema!.displayName!)
+ CurrentUserUtils.ActiveSchemaName = CurrentUserUtils.ActiveSchema!.displayName!;
}
}
async initializeNorthstar(): Promise {
diff --git a/src/client/views/nodes/HistogramBox.tsx b/src/client/views/nodes/HistogramBox.tsx
index 675bf30b2..73d3f3bc3 100644
--- a/src/client/views/nodes/HistogramBox.tsx
+++ b/src/client/views/nodes/HistogramBox.tsx
@@ -1,17 +1,17 @@
import React = require("react")
-import { computed, observable, reaction, runInAction } from "mobx";
+import { computed, observable, reaction, runInAction, action, observe } from "mobx";
import { observer } from "mobx-react";
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 { ColumnAttributeModel, AttributeModel } from "../../northstar/core/attribute/AttributeModel";
import { AttributeTransformationModel } from "../../northstar/core/attribute/AttributeTransformationModel";
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 { AggregateBinRange, AggregateFunction, Bin, Brush, DoubleValueAggregateResult, HistogramResult, MarginAggregateParameters, MarginAggregateResult, Attribute, BinRange } from "../../northstar/model/idea/idea";
import { ModelHelpers } from "../../northstar/model/ModelHelpers";
import { HistogramOperation } from "../../northstar/operations/HistogramOperation";
import { ArrayUtil } from "../../northstar/utils/ArrayUtil";
@@ -22,6 +22,10 @@ import { StyleConstants } from "../../northstar/utils/StyleContants";
import { FieldView, FieldViewProps } from './FieldView';
import "./HistogramBox.scss";
import { KeyStore } from "../../../fields/KeyStore";
+import { ListField } from "../../../fields/ListField";
+import { Document } from "../../../fields/Document"
+import { HistogramField } from "../../../fields/HistogramField";
+import { FieldWaiting, Opt } from "../../../fields/Field";
@observer
export class HistogramBox extends React.Component {
@@ -38,37 +42,26 @@ export class HistogramBox extends React.Component {
@observable public ChartType: ChartType = ChartType.VerticalBar;
public HitTargets: Dictionary = new Dictionary();
- constructor(props: FieldViewProps) {
- super(props);
- }
-
@computed get xaxislines() { return this.renderGridLinesAndLabels(0); }
@computed get yaxislines() { return this.renderGridLinesAndLabels(1); }
componentDidMount() {
- reaction(() => CurrentUserUtils.GetAllNorthstarColumnAttributes().filter(a => a.displayName == this.props.doc.Title),
- (columnAttrs) => columnAttrs.map(a => {
- 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(() => [CurrentUserUtils.ActiveSchemaName, this.props.doc.GetText(KeyStore.NorthstarSchema, "?")],
+ () => CurrentUserUtils.ActiveSchemaName == this.props.doc.GetText(KeyStore.NorthstarSchema, "?") && this.activateHistogramOperation(),
+ { 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)
+ reaction(() => this.HistoOp && this.HistoOp.Result instanceof HistogramResult ? this.HistoOp.Result.binRanges : undefined,
+ (binRanges: BinRange[] | undefined) => {
+ if (!binRanges || !this.HistoOp || !(this.HistoOp!.Result instanceof HistogramResult))
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));
+ 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;
@@ -89,6 +82,29 @@ export class HistogramBox extends React.Component {
);
}
+ @computed
+ get createOperationParamsCache() {
+ return this.HistoOp!.CreateOperationParameters();
+ }
+
+ activateHistogramOperation() {
+ this.props.doc.GetTAsync(this.props.fieldKey, HistogramField).then((histoOp: Opt) => {
+ if (histoOp) {
+ runInAction(() => this.HistoOp = histoOp.Data);
+ this.HistoOp!.Update();
+ reaction(() => this.createOperationParamsCache, () => this.HistoOp!.Update());
+ reaction(() => this.props.doc.GetList(KeyStore.LinkedFromDocs, []),
+ () => {
+ let linkFrom: Document[] = this.props.doc.GetData(KeyStore.LinkedFromDocs, ListField, []);
+ this.HistoOp!.Links.length = 0;
+ linkFrom.map(l => this.HistoOp!.Links.push(l.GetData(KeyStore.Data, HistogramField, HistogramOperation.Empty)));
+ },
+ { fireImmediately: true }
+ );
+ }
+ })
+ }
+
drawLine(xFrom: number, yFrom: number, width: number, height: number) {
return ;
}
diff --git a/src/fields/HistogramField.ts b/src/fields/HistogramField.ts
new file mode 100644
index 000000000..bb0014ab3
--- /dev/null
+++ b/src/fields/HistogramField.ts
@@ -0,0 +1,59 @@
+import { BasicField } from "./BasicField";
+import { Field, FieldId } from "./Field";
+import { Types } from "../server/Message";
+import { HistogramOperation } from "../client/northstar/operations/HistogramOperation";
+import { action } from "mobx";
+import { AttributeTransformationModel } from "../client/northstar/core/attribute/AttributeTransformationModel";
+import { ColumnAttributeModel } from "../client/northstar/core/attribute/AttributeModel";
+import { CurrentUserUtils } from "../server/authentication/models/current_user_utils";
+
+
+export class HistogramField extends BasicField {
+ constructor(data?: HistogramOperation, id?: FieldId, save: boolean = true) {
+ super(data ? data : HistogramOperation.Empty, save, id);
+ }
+
+ toString(): string {
+ return JSON.stringify(this.Data);
+ }
+
+ Copy(): Field {
+ return new HistogramField(this.Data);
+ }
+
+ ToScriptString(): string {
+ return `new HistogramField("${this.Data}")`;
+ }
+
+ ToJson(): { type: Types, data: string, _id: string } {
+ return {
+ type: Types.HistogramOp,
+ data: JSON.stringify(this.Data),
+ _id: this.Id
+ }
+ }
+
+ @action
+ static FromJson(id: string, data: any): HistogramField {
+ let jp = JSON.parse(data);
+ let X: AttributeTransformationModel | undefined;
+ let Y: AttributeTransformationModel | undefined;
+ let V: AttributeTransformationModel | undefined;
+
+ CurrentUserUtils.GetAllNorthstarColumnAttributes().map(attr => {
+ if (attr.displayName == jp.X.AttributeModel.Attribute.DisplayName) {
+ X = new AttributeTransformationModel(new ColumnAttributeModel(attr), jp.X.AggregateFunction);
+ }
+ if (attr.displayName == jp.Y.AttributeModel.Attribute.DisplayName) {
+ Y = new AttributeTransformationModel(new ColumnAttributeModel(attr), jp.Y.AggregateFunction);
+ }
+ if (attr.displayName == jp.V.AttributeModel.Attribute.DisplayName) {
+ V = new AttributeTransformationModel(new ColumnAttributeModel(attr), jp.V.AggregateFunction);
+ }
+ });
+ if (X && Y && V) {
+ return new HistogramField(new HistogramOperation(X, Y, V, jp.Normalization), id, false);
+ }
+ return new HistogramField(HistogramOperation.Empty, id, false);
+ }
+}
\ No newline at end of file
diff --git a/src/fields/KeyStore.ts b/src/fields/KeyStore.ts
index f9684b212..20e8cd930 100644
--- a/src/fields/KeyStore.ts
+++ b/src/fields/KeyStore.ts
@@ -29,7 +29,6 @@ export namespace KeyStore {
export const Caption = new Key("Caption");
export const ActiveFrame = new Key("ActiveFrame");
export const ActiveWorkspace = new Key("ActiveWorkspace");
- export const ActiveDB = new Key("ActiveDB");
export const DocumentText = new Key("DocumentText");
export const LinkedToDocs = new Key("LinkedToDocs");
export const LinkedFromDocs = new Key("LinkedFromDocs");
@@ -46,4 +45,5 @@ export namespace KeyStore {
export const Archives = new Key("Archives");
export const Updated = new Key("Updated");
export const Workspaces = new Key("Workspaces");
+ export const NorthstarSchema = new Key("NorthstarSchema");
}
diff --git a/src/server/Message.ts b/src/server/Message.ts
index a2d1ab829..05ae0f19a 100644
--- a/src/server/Message.ts
+++ b/src/server/Message.ts
@@ -45,7 +45,7 @@ export class GetFieldArgs {
}
export enum Types {
- Number, List, Key, Image, Web, Document, Text, RichText, DocumentReference, Html, Video, Audio, Ink, PDF, Tuple
+ Number, List, Key, Image, Web, Document, Text, RichText, DocumentReference, Html, Video, Audio, Ink, PDF, Tuple, HistogramOp
}
export class DocumentTransfer implements Transferable {
diff --git a/src/server/ServerUtil.ts b/src/server/ServerUtil.ts
index f10f82deb..f958df04b 100644
--- a/src/server/ServerUtil.ts
+++ b/src/server/ServerUtil.ts
@@ -17,6 +17,7 @@ import { VideoField } from '../fields/VideoField';
import { InkField } from '../fields/InkField';
import { PDFField } from '../fields/PDFField';
import { TupleField } from '../fields/TupleField';
+import { HistogramField } from '../fields/HistogramField';
@@ -50,6 +51,8 @@ export class ServerUtils {
return new Key(data, id, false)
case Types.Image:
return new ImageField(new URL(data), id, false)
+ case Types.HistogramOp:
+ return HistogramField.FromJson(id, data);
case Types.PDF:
return new PDFField(new URL(data), id, false)
case Types.List:
diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts
index 055e4cc97..4b42e40b6 100644
--- a/src/server/authentication/models/current_user_utils.ts
+++ b/src/server/authentication/models/current_user_utils.ts
@@ -8,6 +8,7 @@ import { KeyStore } from "../../../fields/KeyStore";
import { ListField } from "../../../fields/ListField";
import { Documents } from "../../../client/documents/Documents";
import { Schema, Attribute, AttributeGroup } from "../../../client/northstar/model/idea/idea";
+import { observable, computed, action } from "mobx";
export class CurrentUserUtils {
private static curr_email: string;
@@ -16,6 +17,7 @@ export class CurrentUserUtils {
//TODO tfs: these should be temporary...
private static mainDocId: string | undefined;
private static activeSchema: Schema | undefined;
+ @observable public static ActiveSchemaName: string = "";
public static get email(): string {
return this.curr_email;
@@ -37,6 +39,7 @@ export class CurrentUserUtils {
this.mainDocId = id;
}
+
public static get ActiveSchema(): Schema | undefined {
return this.activeSchema;
}
--
cgit v1.2.3-70-g09d2
From b9d23e5adde2da01708cc8501ca375726d232d06 Mon Sep 17 00:00:00 2001
From: bob
Date: Tue, 26 Mar 2019 13:56:50 -0400
Subject: some filtering
---
src/client/northstar/core/filter/FilterModel.ts | 48 +++++++++++++++++-
.../northstar/core/filter/IBaseFilterConsumer.ts | 4 +-
src/client/northstar/operations/BaseOperation.ts | 2 +
.../northstar/operations/HistogramOperation.ts | 57 +++++++++++++++-------
src/client/views/nodes/HistogramBox.tsx | 35 +++++++------
5 files changed, 110 insertions(+), 36 deletions(-)
(limited to 'src/client/northstar/operations')
diff --git a/src/client/northstar/core/filter/FilterModel.ts b/src/client/northstar/core/filter/FilterModel.ts
index 01bf2a809..a9c79d245 100644
--- a/src/client/northstar/core/filter/FilterModel.ts
+++ b/src/client/northstar/core/filter/FilterModel.ts
@@ -1,8 +1,13 @@
import { ValueComparison } from "./ValueComparision";
import { Utils } from "../../utils/Utils";
-import { IBaseFilterProvider } from "./IBaseFilterProvider";
+import { IBaseFilterProvider, instanceOfIBaseFilterProvider } from "./IBaseFilterProvider";
import { BaseOperation } from "../../operations/BaseOperation";
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";
export class FilterModel {
public ValueComparisons: ValueComparison[];
@@ -38,6 +43,47 @@ export class FilterModel {
let ret = filters.filter(f => f !== "").join(" && ");
return ret;
}
+ public static GetFilterModelsRecursive(baseOperation: IBaseFilterProvider, visitedFilterProviders: Set, filterModels: FilterModel[], isFirst: boolean): string {
+ let ret = "";
+ 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();
+ let linkedGraphNodes = baseOperation.Links;
+ linkedGraphNodes.map(linkVm => {
+ let filterDoc = linkVm.Get(KeyStore.LinkedFromDocs);
+ if (filterDoc && filterDoc != FieldWaiting && filterDoc instanceof Document) {
+ let filterHistogram = filterDoc.GetT(KeyStore.Data, HistogramField);
+ if (filterHistogram && filterHistogram != FieldWaiting) {
+ if (!visitedFilterProviders.has(filterHistogram.Data)) {
+ let child = FilterModel.GetFilterModelsRecursive(filterHistogram.Data, 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;
+ }
// public static GetFilterModelsRecursive(baseOperation: BaseOperation,
// visitedFilterProviders: Set, filterModels: FilterModel[], isFirst: boolean): string {
diff --git a/src/client/northstar/core/filter/IBaseFilterConsumer.ts b/src/client/northstar/core/filter/IBaseFilterConsumer.ts
index 3eb32b6db..93f66a154 100644
--- a/src/client/northstar/core/filter/IBaseFilterConsumer.ts
+++ b/src/client/northstar/core/filter/IBaseFilterConsumer.ts
@@ -1,10 +1,10 @@
import { FilterOperand } from '../filter/FilterOperand'
import { IEquatable } from '../../utils/IEquatable'
-import { IBaseFilterProvider } from './IBaseFilterProvider';
+import { Document } from "../../../../fields/Document";
export interface IBaseFilterConsumer extends IEquatable {
FilterOperand: FilterOperand;
- Links: IBaseFilterProvider[];
+ Links: Document[];
}
export function instanceOfIBaseFilterConsumer(object: any): object is IBaseFilterConsumer {
diff --git a/src/client/northstar/operations/BaseOperation.ts b/src/client/northstar/operations/BaseOperation.ts
index 4c0303a48..4bc8873d5 100644
--- a/src/client/northstar/operations/BaseOperation.ts
+++ b/src/client/northstar/operations/BaseOperation.ts
@@ -25,6 +25,8 @@ export abstract class BaseOperation {
@computed
public get FilterString(): string {
+ // let filterModels: FilterModel[] = [];
+ // return FilterModel.GetFilterModelsRecursive(this, new Set>(), filterModels, true)
// if (this.OverridingFilters.length > 0) {
// return "(" + this.OverridingFilters.filter(fm => fm != null).map(fm => fm.ToPythonString()).join(" || ") + ")";
// }
diff --git a/src/client/northstar/operations/HistogramOperation.ts b/src/client/northstar/operations/HistogramOperation.ts
index 0c38679e5..93946b296 100644
--- a/src/client/northstar/operations/HistogramOperation.ts
+++ b/src/client/northstar/operations/HistogramOperation.ts
@@ -1,23 +1,24 @@
-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";
-import { ModelHelpers } from "../model/ModelHelpers";
-import { SETTINGS_X_BINS, SETTINGS_Y_BINS, SETTINGS_SAMPLE_SIZE } from "../model/binRanges/VisualBinRangeHelper";
-import { AttributeTransformationModel } from "../core/attribute/AttributeTransformationModel";
-import { BaseOperation } from "./BaseOperation";
+import { action, computed, observable } from "mobx";
+import { Document } from "../../../fields/Document";
import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils";
-import { FilterModel } from "../core/filter/FilterModel";
+import { ColumnAttributeModel } from "../core/attribute/AttributeModel";
+import { AttributeTransformationModel } from "../core/attribute/AttributeTransformationModel";
+import { CalculatedAttributeManager } from "../core/attribute/CalculatedAttributeModel";
import { BrushLinkModel } from "../core/brusher/BrushLinkModel";
-import { IBaseFilterConsumer } from "../core/filter/IBaseFilterConsumer";
+import { FilterModel } from "../core/filter/FilterModel";
import { FilterOperand } from "../core/filter/FilterOperand";
+import { IBaseFilterConsumer } from "../core/filter/IBaseFilterConsumer";
import { IBaseFilterProvider } from "../core/filter/IBaseFilterProvider";
-import { AttributeModel, ColumnAttributeModel } from "../core/attribute/AttributeModel";
+import { SETTINGS_SAMPLE_SIZE, SETTINGS_X_BINS, SETTINGS_Y_BINS } from "../model/binRanges/VisualBinRangeHelper";
+import { AggregateFunction, AggregateParameters, Attribute, AverageAggregateParameters, DataType, HistogramOperationParameters, QuantitativeBinRange } from "../model/idea/idea";
+import { ModelHelpers } from "../model/ModelHelpers";
+import { ArrayUtil } from "../utils/ArrayUtil";
+import { BaseOperation } from "./BaseOperation";
export class HistogramOperation extends BaseOperation implements IBaseFilterConsumer, IBaseFilterProvider {
@observable public FilterOperand: FilterOperand = FilterOperand.AND;
- @observable public Links: IBaseFilterProvider[] = [];
+ @observable public Links: Document[] = [];
@observable public BrushColors: number[] = [];
@observable public Normalization: number = -1;
@observable public FilterModels: FilterModel[] = [];
@@ -27,6 +28,15 @@ export class HistogramOperation extends BaseOperation implements IBaseFilterCons
@observable public BrusherModels: BrushLinkModel[] = [];
@observable public BrushableModels: BrushLinkModel[] = [];
+ @action
+ public AddFilterModels(filterModels: FilterModel[]): void {
+ filterModels.filter(f => f !== null).forEach(fm => this.FilterModels.push(fm));
+ }
+ @action
+ public RemoveFilterModels(filterModels: FilterModel[]): void {
+ ArrayUtil.RemoveMany(this.FilterModels, filterModels);
+ }
+
public static Empty = new HistogramOperation(new AttributeTransformationModel(new ColumnAttributeModel(new Attribute())), new AttributeTransformationModel(new ColumnAttributeModel(new Attribute())), new AttributeTransformationModel(new ColumnAttributeModel(new Attribute())));
Equals(other: Object): boolean {
@@ -41,6 +51,19 @@ export class HistogramOperation extends BaseOperation implements IBaseFilterCons
this.Normalization = normalized ? normalized : -1;
}
+ @computed
+ public get FilterString(): string {
+ let filterModels: FilterModel[] = [];
+ let fstring = FilterModel.GetFilterModelsRecursive(this, new Set(), filterModels, true)
+ console.log("Filter string " + this.X.AttributeModel.DisplayName + " = " + fstring);
+ return fstring;
+ }
+ @computed
+ public get OutputFilterString(): string {
+ let filterModels: FilterModel[] = [];
+ return FilterModel.GetFilterModelsRecursive(this, new Set(), filterModels, false)
+ }
+
@computed.struct
public get BrushString() {
return [];
@@ -59,11 +82,11 @@ export class HistogramOperation extends BaseOperation implements IBaseFilterCons
}
- // @computed.struct
- // public get SelectionString() {
- // let filterModels = new Array();
- // return FilterModel.GetFilterModelsRecursive(this, new Set>(), filterModels, false);
- // }
+ @computed.struct
+ public get SelectionString() {
+ let filterModels = new Array();
+ return FilterModel.GetFilterModelsRecursive(this, new Set(), filterModels, false);
+ }
GetAggregateParameters(histoX: AttributeTransformationModel, histoY: AttributeTransformationModel, histoValue: AttributeTransformationModel) {
let allAttributes = new Array(histoX, histoY, histoValue);
diff --git a/src/client/views/nodes/HistogramBox.tsx b/src/client/views/nodes/HistogramBox.tsx
index 73d3f3bc3..e21054e15 100644
--- a/src/client/views/nodes/HistogramBox.tsx
+++ b/src/client/views/nodes/HistogramBox.tsx
@@ -1,17 +1,19 @@
import React = require("react")
-import { computed, observable, reaction, runInAction, action, observe } from "mobx";
+import { computed, observable, reaction, runInAction, trace } from "mobx";
import { observer } from "mobx-react";
import Measure from "react-measure";
import { Dictionary } from "typescript-collections";
+import { Document } from "../../../fields/Document";
+import { Opt } from "../../../fields/Field";
+import { HistogramField } from "../../../fields/HistogramField";
+import { KeyStore } from "../../../fields/KeyStore";
import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils";
import { Utils as DashUtils } from '../../../Utils';
-import { ColumnAttributeModel, AttributeModel } from "../../northstar/core/attribute/AttributeModel";
-import { AttributeTransformationModel } from "../../northstar/core/attribute/AttributeTransformationModel";
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, Attribute, BinRange } from "../../northstar/model/idea/idea";
+import { AggregateBinRange, AggregateFunction, Bin, BinRange, Brush, DoubleValueAggregateResult, HistogramResult, MarginAggregateParameters, MarginAggregateResult } from "../../northstar/model/idea/idea";
import { ModelHelpers } from "../../northstar/model/ModelHelpers";
import { HistogramOperation } from "../../northstar/operations/HistogramOperation";
import { ArrayUtil } from "../../northstar/utils/ArrayUtil";
@@ -21,11 +23,6 @@ import { SizeConverter } from "../../northstar/utils/SizeConverter";
import { StyleConstants } from "../../northstar/utils/StyleContants";
import { FieldView, FieldViewProps } from './FieldView';
import "./HistogramBox.scss";
-import { KeyStore } from "../../../fields/KeyStore";
-import { ListField } from "../../../fields/ListField";
-import { Document } from "../../../fields/Document"
-import { HistogramField } from "../../../fields/HistogramField";
-import { FieldWaiting, Opt } from "../../../fields/Field";
@observer
export class HistogramBox extends React.Component {
@@ -92,12 +89,13 @@ export class HistogramBox extends React.Component {
if (histoOp) {
runInAction(() => this.HistoOp = histoOp.Data);
this.HistoOp!.Update();
- reaction(() => this.createOperationParamsCache, () => this.HistoOp!.Update());
+ reaction(
+ () => this.createOperationParamsCache,
+ () => this.HistoOp!.Update();
reaction(() => this.props.doc.GetList(KeyStore.LinkedFromDocs, []),
- () => {
- let linkFrom: Document[] = this.props.doc.GetData(KeyStore.LinkedFromDocs, ListField, []);
+ (docs: Document[]) => {
this.HistoOp!.Links.length = 0;
- linkFrom.map(l => this.HistoOp!.Links.push(l.GetData(KeyStore.Data, HistogramField, HistogramOperation.Empty)));
+ this.HistoOp!.Links.push(...docs);
},
{ fireImmediately: true }
);
@@ -172,7 +170,6 @@ export class HistogramBox extends React.Component {
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)) {
@@ -180,8 +177,13 @@ export class HistogramBox extends React.Component {
}
drawPrims.BinPrimitives.filter(bp => bp.DataValue && bp.BrushIndex !== allBrushIndex).map(binPrimitive => {
- prims.push(this.drawRect(binPrimitive.Rect, binPrimitive.Color, () => { console.log("FM = " + filterModel.ToPythonString()) }));
- prims.push(this.drawRect(binPrimitive.MarginRect, StyleConstants.MARGIN_BARS_COLOR, () => { console.log("FM = " + filterModel.ToPythonString()) }));
+ 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)));
});
}
}
@@ -189,6 +191,7 @@ export class HistogramBox extends React.Component {
}
render() {
+ trace();
if (!this.binPrimitives || !this.VisualBinRanges.length) {
return (null);
}
--
cgit v1.2.3-70-g09d2
From e9826e0ac334bac28d173f67b4f0db0800b40680 Mon Sep 17 00:00:00 2001
From: bob
Date: Tue, 26 Mar 2019 16:06:06 -0400
Subject: cleaned up a bit. got rid of blinking when histos change.
---
src/client/northstar/core/filter/FilterModel.ts | 50 +--
src/client/northstar/operations/BaseOperation.ts | 3 +-
.../northstar/operations/HistogramOperation.ts | 1 -
src/client/views/nodes/DocumentContentsView.tsx | 3 +-
src/client/views/nodes/HistogramBox.tsx | 360 ++------------------
src/client/views/nodes/HistogramBoxPrimitives.tsx | 373 +++++++++++++++++++++
6 files changed, 399 insertions(+), 391 deletions(-)
create mode 100644 src/client/views/nodes/HistogramBoxPrimitives.tsx
(limited to 'src/client/northstar/operations')
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, 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();
- // 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(), 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.ComponentError loading layout keys
;
}
return {
@@ -41,6 +40,7 @@ export class HistogramBox extends React.Component {
@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 {
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 {
);
}
- @computed
- get createOperationParamsCache() {
- return this.HistoOp!.CreateOperationParameters();
- }
-
activateHistogramOperation() {
this.props.doc.GetTAsync(this.props.fieldKey, HistogramField).then((histoOp: Opt) => {
if (histoOp) {
@@ -91,7 +86,7 @@ export class HistogramBox extends React.Component {
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 {
return ;
}
- drawRect(r: PIXIRectangle, color: number, tapHandler: () => void) {
- return
- }
-
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) : // (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))); // (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 {
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 {
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();
- 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 (
runInAction(() => { this._panelWidth = r.entry.width; this._panelHeight = r.entry.height })}>
{({ measureRef }) =>
- {this.xaxislines}
- {this.yaxislines}
- {this.binPrimitives}
-
{this.HistoOp!.X.AttributeModel.DisplayName}
+ {xaxislines}
+ {yaxislines}
+
+
{label}
}
)
}
-}
-
-export class HistogramBinPrimitive {
- constructor(init?: Partial) {
- 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 = new Array();
- 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();
- 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, 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 {
+ @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(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(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
+ }
+
+ drawRect(r: PIXIRectangle, color: number, tapHandler: () => void) {
+ return
+ }
+ render() {
+ return
+ {this.binPrimitives}
+ {this.selectedPrimitives}
+
+ }
+}
+
+
+class HistogramBinPrimitive {
+ constructor(init?: Partial) {
+ 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 = new Array();
+ 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();
+ 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, 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
--
cgit v1.2.3-70-g09d2
From f51ca77dcea14bafe4126b5cf7b092db6d3c2c5b Mon Sep 17 00:00:00 2001
From: Bob Zeleznik
Date: Tue, 26 Mar 2019 22:37:24 -0400
Subject: a bunch more cleanup
---
.../northstar/operations/HistogramOperation.ts | 13 +-
src/client/northstar/utils/Extensions.ts | 9 +
src/client/northstar/utils/SizeConverter.ts | 35 +++
src/client/views/Main.tsx | 4 -
src/client/views/nodes/HistogramBox.tsx | 94 ++----
src/client/views/nodes/HistogramBoxPrimitives.scss | 10 +
src/client/views/nodes/HistogramBoxPrimitives.tsx | 333 ++++++++-------------
7 files changed, 222 insertions(+), 276 deletions(-)
create mode 100644 src/client/views/nodes/HistogramBoxPrimitives.scss
(limited to 'src/client/northstar/operations')
diff --git a/src/client/northstar/operations/HistogramOperation.ts b/src/client/northstar/operations/HistogramOperation.ts
index bceadb961..6c7288d42 100644
--- a/src/client/northstar/operations/HistogramOperation.ts
+++ b/src/client/northstar/operations/HistogramOperation.ts
@@ -10,7 +10,7 @@ import { FilterOperand } from "../core/filter/FilterOperand";
import { IBaseFilterConsumer } from "../core/filter/IBaseFilterConsumer";
import { IBaseFilterProvider } from "../core/filter/IBaseFilterProvider";
import { SETTINGS_SAMPLE_SIZE, SETTINGS_X_BINS, SETTINGS_Y_BINS } from "../model/binRanges/VisualBinRangeHelper";
-import { AggregateFunction, AggregateParameters, Attribute, AverageAggregateParameters, DataType, HistogramOperationParameters, QuantitativeBinRange } from "../model/idea/idea";
+import { AggregateFunction, AggregateParameters, Attribute, AverageAggregateParameters, DataType, HistogramOperationParameters, QuantitativeBinRange, HistogramResult, Brush, DoubleValueAggregateResult, Bin } from "../model/idea/idea";
import { ModelHelpers } from "../model/ModelHelpers";
import { ArrayUtil } from "../utils/ArrayUtil";
import { BaseOperation } from "./BaseOperation";
@@ -37,6 +37,12 @@ export class HistogramOperation extends BaseOperation implements IBaseFilterCons
ArrayUtil.RemoveMany(this.FilterModels, filterModels);
}
+ public getValue(axis: number, bin: Bin, result: HistogramResult, brushIndex: number) {
+ var aggregateKey = ModelHelpers.CreateAggregateKey(axis == 0 ? this.X : axis == 1 ? this.Y : this.V, result, brushIndex);
+ let dataValue = ModelHelpers.GetAggregateResult(bin, aggregateKey) as DoubleValueAggregateResult;
+ return dataValue != null && dataValue.hasResult ? dataValue.result : undefined;
+ }
+
public static Empty = new HistogramOperation(new AttributeTransformationModel(new ColumnAttributeModel(new Attribute())), new AttributeTransformationModel(new ColumnAttributeModel(new Attribute())), new AttributeTransformationModel(new ColumnAttributeModel(new Attribute())));
Equals(other: Object): boolean {
@@ -57,11 +63,6 @@ export class HistogramOperation extends BaseOperation implements IBaseFilterCons
let fstring = FilterModel.GetFilterModelsRecursive(this, new Set(), filterModels, true)
return fstring;
}
- @computed
- public get OutputFilterString(): string {
- let filterModels: FilterModel[] = [];
- return FilterModel.GetFilterModelsRecursive(this, new Set(), filterModels, false)
- }
@computed.struct
public get BrushString() {
diff --git a/src/client/northstar/utils/Extensions.ts b/src/client/northstar/utils/Extensions.ts
index 71bcadf89..7c2b7fc9d 100644
--- a/src/client/northstar/utils/Extensions.ts
+++ b/src/client/northstar/utils/Extensions.ts
@@ -1,5 +1,6 @@
interface String {
ReplaceAll(toReplace: string, replacement: string): string;
+ Truncate(length: number, replacement: string): String;
}
String.prototype.ReplaceAll = function (toReplace: string, replacement: string): string {
@@ -7,6 +8,14 @@ String.prototype.ReplaceAll = function (toReplace: string, replacement: string):
return target.split(toReplace).join(replacement);
}
+String.prototype.Truncate = function (length: number, replacement: string): String {
+ var target = this;
+ if (target.length >= length) {
+ target = target.slice(0, Math.max(0, length - replacement.length)) + replacement;
+ }
+ return target;
+}
+
interface Math {
log10(val: number): number;
}
diff --git a/src/client/northstar/utils/SizeConverter.ts b/src/client/northstar/utils/SizeConverter.ts
index e8973cfd5..2dc2a7557 100644
--- a/src/client/northstar/utils/SizeConverter.ts
+++ b/src/client/northstar/utils/SizeConverter.ts
@@ -1,6 +1,9 @@
import { PIXIPoint } from "./MathUtil";
import { NominalVisualBinRange } from "../model/binRanges/NominalVisualBinRange";
import { VisualBinRange } from "../model/binRanges/VisualBinRange";
+import { Bin, DoubleValueAggregateResult, AggregateKey } from "../model/idea/idea";
+import { AttributeTransformationModel } from "../core/attribute/AttributeTransformationModel";
+import { ModelHelpers } from "../model/ModelHelpers";
export class SizeConverter {
public RenderSize: Array = new Array(2);
@@ -70,6 +73,26 @@ export class SizeConverter {
this.DataRanges[1] = this.DataMaxs[1] - this.DataMins[1];
}
+ public DataToScreenNormalizedRange(dataValue: number, normalization: number, axis: number, binBrushMaxAxis: number) {
+ var value = normalization != 1 - axis || binBrushMaxAxis == 0 ? dataValue : (dataValue - 0) / (binBrushMaxAxis - 0) * this.DataRanges[axis];
+ var from = this.DataToScreenCoord(Math.min(0, value), axis);
+ var to = this.DataToScreenCoord(Math.max(0, value), axis);
+ return [from, value, to];
+ }
+
+ public DataToScreenPointRange(axis: number, bin: Bin, aggregateKey: AggregateKey) {
+ var value = ModelHelpers.GetAggregateResult(bin, aggregateKey) as DoubleValueAggregateResult;
+ if (value.hasResult)
+ return [this.DataToScreenCoord(value.result!, axis) - 5,
+ this.DataToScreenCoord(value.result!, axis) + 5];
+ return [undefined, undefined];
+ }
+
+ public DataToScreenAxisRange(visualBinRanges: VisualBinRange[], index: number, bin: Bin) {
+ var value = visualBinRanges[0].GetValueFromIndex(bin.binIndex!.indices![index]);
+ return [this.DataToScreenX(value), this.DataToScreenX(visualBinRanges[index].AddStep(value))]
+ }
+
public DataToScreenX(x: number): number {
return (((x - this.DataMins[0]) / this.DataRanges[0]) * (this.RenderSize[0]) + (this.LeftOffset));
}
@@ -77,4 +100,16 @@ export class SizeConverter {
var retY = ((y - this.DataMins[1]) / this.DataRanges[1]) * (this.RenderSize[1]);
return flip ? (this.RenderSize[1]) - retY + (this.TopOffset) : retY + (this.TopOffset);
}
+ public DataToScreenCoord(v: number, axis: number) {
+ if (axis == 0)
+ return this.DataToScreenX(v);
+ return this.DataToScreenY(v);
+ }
+ public DataToScreenRange(minVal: number, maxVal: number, axis: number) {
+ let xFrom = this.DataToScreenX(axis === 0 ? minVal : this.DataMins[0]);
+ let xTo = this.DataToScreenX(axis === 0 ? maxVal : this.DataMaxs[0]);
+ let yFrom = this.DataToScreenY(axis === 1 ? minVal : this.DataMins[1]);
+ let yTo = this.DataToScreenY(axis === 1 ? maxVal : this.DataMaxs[1]);
+ return { xFrom, yFrom, xTo, yTo }
+ }
}
\ No newline at end of file
diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx
index 3e0e02f42..87d8eb648 100644
--- a/src/client/views/Main.tsx
+++ b/src/client/views/Main.tsx
@@ -89,10 +89,6 @@ export class Main extends React.Component {
}
};
- // this.initializeNorthstar();
- let y = "";
- y.ReplaceAll("a", "B");
-
CurrentUserUtils.loadCurrentUser();
library.add(faFont);
diff --git a/src/client/views/nodes/HistogramBox.tsx b/src/client/views/nodes/HistogramBox.tsx
index 4d7922c1b..c9537bcf8 100644
--- a/src/client/views/nodes/HistogramBox.tsx
+++ b/src/client/views/nodes/HistogramBox.tsx
@@ -1,9 +1,8 @@
import React = require("react")
-import { computed, observable, reaction, runInAction, trace } from "mobx";
+import { computed, observable, reaction, runInAction } from "mobx";
import { observer } from "mobx-react";
import Measure from "react-measure";
import { Dictionary } from "typescript-collections";
-import { Document } from "../../../fields/Document";
import { Opt } from "../../../fields/Field";
import { HistogramField } from "../../../fields/HistogramField";
import { KeyStore } from "../../../fields/KeyStore";
@@ -19,81 +18,60 @@ import { HistogramOperation } from "../../northstar/operations/HistogramOperatio
import { PIXIRectangle } from "../../northstar/utils/MathUtil";
import { SizeConverter } from "../../northstar/utils/SizeConverter";
import { StyleConstants } from "../../northstar/utils/StyleContants";
+import "./../../northstar/utils/Extensions";
import { FieldView, FieldViewProps } from './FieldView';
import "./HistogramBox.scss";
import { HistogramBoxPrimitives } from './HistogramBoxPrimitives';
@observer
export class HistogramBox extends React.Component {
-
public static LayoutString(fieldStr: string = "DataKey") { return FieldView.LayoutString(HistogramBox, fieldStr) }
@observable private _panelWidth: number = 100;
@observable private _panelHeight: number = 100;
@observable public HistoOp?: HistogramOperation;
@observable public VisualBinRanges: VisualBinRange[] = [];
- @observable public MinValue: number = 0;
- @observable public MaxValue: number = 0;
+ @observable public ValueRange: number[] = [];
@observable public SizeConverter?: SizeConverter;
- @observable public ChartType: ChartType = ChartType.VerticalBar;
public HitTargets: Dictionary = new Dictionary();
@computed get xaxislines() { return this.renderGridLinesAndLabels(0); }
@computed get yaxislines() { return this.renderGridLinesAndLabels(1); }
@computed get createOperationParamsCache() { return this.HistoOp!.CreateOperationParameters(); }
+ @computed get HistogramResult() { return this.HistoOp ? this.HistoOp.Result as HistogramResult : undefined; }
+ @computed get BinRanges() { return this.HistogramResult ? this.HistogramResult.binRanges : undefined; }
+ @computed get ChartType() {
+ return !this.BinRanges ? ChartType.SinglePoint : this.BinRanges[0] instanceof AggregateBinRange ?
+ (this.BinRanges[1] instanceof AggregateBinRange ? ChartType.SinglePoint : ChartType.HorizontalBar) :
+ this.BinRanges[1] instanceof AggregateBinRange ? ChartType.VerticalBar : ChartType.HeatMap;
+ }
componentDidMount() {
reaction(() => [CurrentUserUtils.ActiveSchemaName, this.props.doc.GetText(KeyStore.NorthstarSchema, "?")],
- () => CurrentUserUtils.ActiveSchemaName == this.props.doc.GetText(KeyStore.NorthstarSchema, "?") && this.activateHistogramOperation(),
- { fireImmediately: true });
+ (params: string[]) => params[0] == params[1] && this.activateHistogramOperation(), { 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 instanceof HistogramResult ? this.HistoOp.Result.binRanges : undefined,
- (binRanges: BinRange[] | undefined) => {
- if (!binRanges || !this.HistoOp || !(this.HistoOp!.Result instanceof HistogramResult))
- return;
-
- 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(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;
- 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!);
- }
- }
- }
- }
+ reaction(() => this.BinRanges, (binRanges: BinRange[] | undefined) => {
+ if (binRanges && this.HistogramResult && !this.HistogramResult!.isEmpty && this.HistogramResult!.bins) {
+ this.VisualBinRanges.splice(0, this.VisualBinRanges.length, ...binRanges.map(br =>
+ VisualBinRangeHelper.GetVisualBinRange(br, this.HistogramResult!, this.HistoOp!.X, this.ChartType)));
+
+ let valueAggregateKey = ModelHelpers.CreateAggregateKey(this.HistoOp!.V, this.HistogramResult!, ModelHelpers.AllBrushIndex(this.HistogramResult!));
+ this.ValueRange = Object.values(this.HistogramResult!.bins).reduce((prev, cur) => {
+ let value = ModelHelpers.GetAggregateResult(cur, valueAggregateKey) as DoubleValueAggregateResult;
+ return value && value.hasResult ? [Math.min(prev[0], value.result!), Math.max(prev[1], value.result!)] : prev;
+ }, [Number.MIN_VALUE, Number.MAX_VALUE]);
}
- );
+ });
}
activateHistogramOperation() {
this.props.doc.GetTAsync(this.props.fieldKey, HistogramField).then((histoOp: Opt) => {
if (histoOp) {
runInAction(() => this.HistoOp = histoOp.Data);
- this.HistoOp!.Update();
- reaction(
- () => this.createOperationParamsCache,
- () => this.HistoOp!.Update());
reaction(() => this.props.doc.GetList(KeyStore.LinkedFromDocs, []),
- (docs: Document[]) => {
- this.HistoOp!.Links.length = 0;
- this.HistoOp!.Links.push(...docs);
- },
- { fireImmediately: true }
- );
+ docs => this.HistoOp!.Links.splice(0, this.HistoOp!.Links.length, ...docs), { fireImmediately: true });
+ reaction(() => this.createOperationParamsCache, () => this.HistoOp!.Update(), { fireImmediately: true });
}
})
}
@@ -113,33 +91,27 @@ export class HistogramBox extends React.Component {
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]);
- let yFrom = sc.DataToScreenY(axis === 0 ? sc.DataMins[1] : binLabel.minValue!);
- let yTo = sc.DataToScreenY(axis === 0 ? sc.DataMaxs[1] : binLabel.maxValue!);
+ let r = sc.DataToScreenRange(binLabel.minValue!, binLabel.maxValue!, axis);
- prims.push(this.drawLine(xFrom, yFrom, axis == 0 ? 1 : xTo - xFrom, axis == 0 ? yTo - yFrom : 1));
+ prims.push(this.drawLine(r.xFrom, r.yFrom, axis == 0 ? 1 : r.xTo - r.xFrom, axis == 0 ? r.yTo - r.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));
+ prims.push(this.drawLine(axis == 0 ? r.xTo : r.xFrom, axis == 0 ? r.yFrom : r.yTo, axis == 0 ? 1 : r.xTo - r.xFrom, axis == 0 ? r.yTo - r.yFrom : 1));
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) + "...";
- }
+ const label = binLabel.label.Truncate(StyleConstants.MAX_CHAR_FOR_HISTOGRAM_LABELS, "...");
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 xStart = (axis === 0 ? r.xFrom + (r.xTo - r.xFrom) / 2.0 : r.xFrom - 10 - textWidth);
+ let yStart = (axis === 1 ? r.yFrom - textHeight / 2 : r.yFrom);
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;
+ rotation = Math.min(90, Math.max(30, textWidth / (r.xTo - r.xFrom) * 90));
+ xStart += Math.max(textWidth / 2, (1 - textWidth / (r.xTo - r.xFrom)) * textWidth / 2) - textHeight / 2;
}
prims.push(
- {text}
+ {label}
)
}
});
diff --git a/src/client/views/nodes/HistogramBoxPrimitives.scss b/src/client/views/nodes/HistogramBoxPrimitives.scss
new file mode 100644
index 000000000..c88d3a227
--- /dev/null
+++ b/src/client/views/nodes/HistogramBoxPrimitives.scss
@@ -0,0 +1,10 @@
+.histogramboxprimitives-border {
+ border: 1px;
+ border-style: solid;
+ pointer-events: none;
+ position: absolute;
+ border-color: #282828;
+}
+.histogramboxprimitives-bar {
+ position: absolute;
+}
\ No newline at end of file
diff --git a/src/client/views/nodes/HistogramBoxPrimitives.tsx b/src/client/views/nodes/HistogramBoxPrimitives.tsx
index a8ada99a4..8c5969938 100644
--- a/src/client/views/nodes/HistogramBoxPrimitives.tsx
+++ b/src/client/views/nodes/HistogramBoxPrimitives.tsx
@@ -1,18 +1,17 @@
import React = require("react")
+import { computed, observable, runInAction } from "mobx";
+import { observer } from "mobx-react";
+import { Utils as DashUtils } from '../../../Utils';
+import { AttributeTransformationModel } from "../../northstar/core/attribute/AttributeTransformationModel";
import { ChartType } from '../../northstar/model/binRanges/VisualBinRange';
-import { AggregateFunction, Bin, Brush, DoubleValueAggregateResult, HistogramResult, MarginAggregateParameters, MarginAggregateResult } from "../../northstar/model/idea/idea";
+import { AggregateFunction, Bin, Brush, HistogramResult, MarginAggregateParameters, MarginAggregateResult } from "../../northstar/model/idea/idea";
import { ModelHelpers } from "../../northstar/model/ModelHelpers";
+import { ArrayUtil } from "../../northstar/utils/ArrayUtil";
import { LABColor } from '../../northstar/utils/LABcolor';
import { PIXIRectangle } from "../../northstar/utils/MathUtil";
-import { 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";
-
+import "./HistogramBox.scss";
export interface HistogramBoxPrimitivesProps {
HistoBox: HistogramBox;
@@ -24,80 +23,63 @@ export class HistogramBoxPrimitives extends React.Component this.drawBorder(bp.Rect, StyleConstants.OPERATOR_BACKGROUND_COLOR));
+ return this._selectedPrims.map((bp) => this.drawRect(bp.Rect, undefined, () => { }, "border"));
}
@computed
get binPrimitives() {
- if (!this.props.HistoBox.HistoOp || !(this.props.HistoBox.HistoOp.Result instanceof HistogramResult) || !this.props.HistoBox.SizeConverter)
+ let histoOp = this.props.HistoBox.HistoOp;
+ let histoResult = this.props.HistoBox.HistogramResult;
+ if (!histoOp || !histoResult || !this.props.HistoBox.SizeConverter || !histoResult.bins)
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(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(drawPrims.BinPrimitives, (bp: HistogramBinPrimitive) => bp.BrushIndex == allBrushIndex);
- if (bp && bp.DataValue) {
- this._selectedPrims.push(bp!);
- }
- this.props.HistoBox.HistoOp!.AddFilterModels([filterModel]);
- }
+ let allBrushIndex = ModelHelpers.AllBrushIndex(histoResult);
+ for (let key in Object.keys(histoResult.bins)) {
+ let drawPrims = new HistogramBinPrimitiveCollection(histoResult.bins![key], this.props.HistoBox);
+ let filterModel = ModelHelpers.GetBinFilterModel(histoResult.bins[key], allBrushIndex, histoResult, histoOp.X, histoOp.Y);
+
+ this.props.HistoBox.HitTargets.setValue(drawPrims.HitGeom, filterModel);
+
+ let allBrushPrim = ArrayUtil.FirstOrDefault(drawPrims.BinPrimitives, (bp: HistogramBinPrimitive) => bp.BrushIndex == allBrushIndex);
+ if (allBrushPrim && allBrushPrim.DataValue) {
+ let toggleFilter = () => {
+ if (ArrayUtil.Contains(histoOp!.FilterModels, filterModel)) {
+ this._selectedPrims.splice(this._selectedPrims.indexOf(allBrushPrim!), 1);
+ histoOp!.RemoveFilterModels([filterModel]);
+ }
+ else {
+ this._selectedPrims.push(allBrushPrim!);
+ 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)));
- });
+ }
+ drawPrims.BinPrimitives.filter(bp => bp.DataValue && bp.BrushIndex !== allBrushIndex).map(bp =>
+ prims.push(
+ this.drawRect(bp.Rect, bp.Color, () => runInAction(toggleFilter), "bar"),
+ this.drawRect(bp.MarginRect, StyleConstants.MARGIN_BARS_COLOR, () => runInAction(toggleFilter), "bar")));
}
}
+
return prims;
}
- drawBorder(r: PIXIRectangle, color: number) {
- return
- }
- drawRect(r: PIXIRectangle, color: number, tapHandler: () => void) {
- return { if (e.button == 0) tapHandler() }}
+ drawRect(r: PIXIRectangle, color: number | undefined, tapHandler: () => void, classExt: string) {
+ return
{ if (e.button == 0) tapHandler() }}
style={{
- position: "absolute",
transform: `translate(${r.x}px,${r.y}px)`,
width: `${r.width - 1}`,
height: `${r.height}`,
- background: `${LABColor.RGBtoHexString(color)}`
+ background: color ? `${LABColor.RGBtoHexString(color)}` : ""
}}
/>
}
render() {
- return
+ return
{this.binPrimitives}
{this.selectedPrimitives}
}
}
-
class HistogramBinPrimitive {
constructor(init?: Partial
) {
Object.assign(this, init);
@@ -117,114 +99,89 @@ export class HistogramBinPrimitiveCollection {
private _histoBox: HistogramBox;
private get histoOp() { return this._histoBox.HistoOp!; }
private get histoResult() { return this.histoOp.Result as HistogramResult; }
+ private get sizeConverter() { return this._histoBox.SizeConverter!; }
public BinPrimitives: Array = new Array();
public HitGeom: PIXIRectangle = PIXIRectangle.EMPTY;
- constructor(key: string, histoBox: HistogramBox) {
+ constructor(bin: Bin, histoBox: HistogramBox) {
this._histoBox = histoBox;
- let bin = this.histoResult.bins![key];
-
- var overlapBrushIndex = ModelHelpers.OverlapBrushIndex(this.histoResult);
- var orderedBrushes = new Array();
- 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);
+ let brushing = this.setupBrushing(bin, this.histoOp.Normalization); // X= 0, Y = 1, V = 2
+
+ brushing.orderedBrushes.reduce((brushFactorSum, brush) => {
+ switch (histoBox.ChartType) {
+ case ChartType.VerticalBar: return this.createVerticalBarChartBinPrimitives(bin, brush, brushing.maxAxis, this.histoOp.Normalization);
+ case ChartType.HorizontalBar: return this.createHorizontalBarChartBinPrimitives(bin, brush, brushing.maxAxis, this.histoOp.Normalization);
+ case ChartType.SinglePoint: return this.createSinglePointChartBinPrimitives(bin, brush);
+ case ChartType.HeatMap: return this.createHeatmapBinPrimitives(bin, brush, brushFactorSum);
}
- }
- 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!);
- }
- }
+ }, 0);
// 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 => {
+ filteredBinPrims.reduce((sum, 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;
+ return sum + fbp.Rect.height;
}
if (this.histoOp.Y.AggregateFunction == AggregateFunction.Avg) {
var w = fbp.Rect.width / 2.0;
- fbp.Rect = new PIXIRectangle(fbp.Rect.x + sum, fbp.Rect.y, fbp.Rect.width / count, fbp.Rect.height);
+ fbp.Rect = new PIXIRectangle(fbp.Rect.x + sum, fbp.Rect.y, fbp.Rect.width / filteredBinPrims.length, fbp.Rect.height);
fbp.MarginRect = new PIXIRectangle(fbp.MarginRect.x - w + sum + (fbp.Rect.width / 2.0), fbp.MarginRect.y, fbp.MarginRect.width, fbp.MarginRect.height);
- sum += fbp.Rect.width;
+ return sum + fbp.Rect.width;
}
}
else if (histoBox.ChartType == ChartType.HorizontalBar) {
if (this.histoOp.X.AggregateFunction == AggregateFunction.Count) {
fbp.Rect = new PIXIRectangle(fbp.Rect.x + sum, fbp.Rect.y, fbp.Rect.width, fbp.Rect.height);
fbp.MarginRect = new PIXIRectangle(fbp.MarginRect.x + sum, fbp.MarginRect.y, fbp.MarginRect.width, fbp.MarginRect.height);
- sum += fbp.Rect.width;
+ return sum + fbp.Rect.width;
}
if (this.histoOp.X.AggregateFunction == AggregateFunction.Avg) {
var h = fbp.Rect.height / 2.0;
- fbp.Rect = new PIXIRectangle(fbp.Rect.x, fbp.Rect.y + sum, fbp.Rect.width, fbp.Rect.height / count);
+ fbp.Rect = new PIXIRectangle(fbp.Rect.x, fbp.Rect.y + sum, fbp.Rect.width, fbp.Rect.height / filteredBinPrims.length);
fbp.MarginRect = new PIXIRectangle(fbp.MarginRect.x, fbp.MarginRect.y - h + sum + (fbp.Rect.height / 2.0), fbp.MarginRect.width, fbp.MarginRect.height);
- sum += fbp.Rect.height;
+ return sum + fbp.Rect.height;
}
}
- });
+ return 0;
+ }, 0);
this.BinPrimitives = this.BinPrimitives.reverse();
var f = this.BinPrimitives.filter(b => b.BrushIndex == allBrushIndex);
this.HitGeom = f.length > 0 ? f[0].Rect : PIXIRectangle.EMPTY;
}
- private getBinBrushAxisRange(bin: Bin, brushes: Array, 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 setupBrushing(bin: Bin, normalization: number) {
+ var overlapBrushIndex = ModelHelpers.OverlapBrushIndex(this.histoResult);
+ var orderedBrushes = [this.histoResult.brushes![0], this.histoResult.brushes![overlapBrushIndex]];
+ this.histoResult.brushes!.map(brush => brush.brushIndex != 0 && brush.brushIndex != overlapBrushIndex && orderedBrushes.push(brush));
+ return {
+ orderedBrushes,
+ maxAxis: orderedBrushes.reduce((prev, Brush) => {
+ let aggResult = this.histoOp.getValue(normalization, bin, this.histoResult, Brush.brushIndex!);
+ return aggResult != undefined && aggResult > prev ? aggResult : prev;
+ }, Number.MIN_VALUE)
+ };
}
- private createHeatmapBinPrimitives(bin: Bin, brush: Brush, unNormalizedValue: number, brushFactorSum: number, normalizedValue: number, sizeConverter: SizeConverter): number {
+ private createHeatmapBinPrimitives(bin: Bin, brush: Brush, brushFactorSum: number): number {
+
+ let unNormalizedValue = this.histoOp!.getValue(2, bin, this.histoResult, brush.brushIndex!);
+ if (unNormalizedValue == undefined)
+ return brushFactorSum;
- var valueAggregateKey = ModelHelpers.CreateAggregateKey(this.histoOp.V, this.histoResult, ModelHelpers.AllBrushIndex(this.histoResult));
- var allUnNormalizedValue = ModelHelpers.GetAggregateResult(bin, valueAggregateKey) as DoubleValueAggregateResult;
+ var normalizedValue = (unNormalizedValue - this._histoBox.ValueRange[0]) / (Math.abs((this._histoBox.ValueRange[1] - this._histoBox.ValueRange[0])) < HistogramBinPrimitiveCollection.TOLERANCE ?
+ unNormalizedValue : this._histoBox.ValueRange[1] - this._histoBox.ValueRange[0]);
- 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));
+ let allUnNormalizedValue = this.histoOp.getValue(2, bin, this.histoResult, ModelHelpers.AllBrushIndex(this.histoResult))
- 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));
+ // bcz: are these calls needed?
+ let [xFrom, xTo] = this.sizeConverter.DataToScreenAxisRange(this._histoBox.VisualBinRanges, 0, bin);
+ let [yFrom, yTo] = this.sizeConverter.DataToScreenAxisRange(this._histoBox.VisualBinRanges, 1, bin);
var returnBrushFactorSum = brushFactorSum;
- if (allUnNormalizedValue.hasResult) {
- var brushFactor = (unNormalizedValue / allUnNormalizedValue.result!);
+ if (allUnNormalizedValue != undefined) {
+ var brushFactor = (unNormalizedValue / allUnNormalizedValue);
returnBrushFactorSum += brushFactor;
returnBrushFactorSum = Math.min(returnBrushFactorSum, 1.0);
@@ -250,95 +207,67 @@ export class HistogramBinPrimitiveCollection {
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;
+ private createSinglePointChartBinPrimitives(bin: Bin, brush: Brush): number {
+ let unNormalizedValue = this._histoBox.HistoOp!.getValue(2, bin, this.histoResult, brush.brushIndex!);
+ if (unNormalizedValue != undefined) {
+ let [xFrom, xTo] = this.sizeConverter.DataToScreenPointRange(0, bin, ModelHelpers.CreateAggregateKey(this.histoOp.X, this.histoResult, brush.brushIndex!));
+ let [yFrom, yTo] = this.sizeConverter.DataToScreenPointRange(1, bin, ModelHelpers.CreateAggregateKey(this.histoOp.Y, this.histoResult, brush.brushIndex!));
- 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);
+ if (xFrom != undefined && yFrom != undefined && xTo != undefined && yTo != undefined)
+ this.createBinPrimitive(bin, brush, PIXIRectangle.EMPTY, 0, xFrom, xTo, yFrom, yTo, this.baseColorFromBrush(brush), 1, unNormalizedValue);
+ }
+ return 0;
}
- private createVerticalBarChartBinPrimitives(bin: Bin, brush: Brush, binBrushMaxAxis: number, normalization: number, 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));
+ private createVerticalBarChartBinPrimitives(bin: Bin, brush: Brush, binBrushMaxAxis: number, normalization: number): number {
+ let dataValue = this.histoOp.getValue(1, bin, this.histoResult, brush.brushIndex!);
+ if (dataValue != undefined) {
+ let [yFrom, yValue, yTo] = this.sizeConverter.DataToScreenNormalizedRange(dataValue, normalization, 1, binBrushMaxAxis);
+ let [xFrom, xTo] = this.sizeConverter.DataToScreenAxisRange(this._histoBox.VisualBinRanges, 0, bin);
- var marginResult = ModelHelpers.GetAggregateResult(bin, yMarginAggregateKey) as MarginAggregateResult;
- var yMarginAbsolute = !marginResult ? 0 : marginResult.absolutMargin!;
+ var yMarginAbsolute = this.getMargin(bin, brush, this.histoOp.Y);
var marginRect = new PIXIRectangle(xFrom + (xTo - xFrom) / 2.0 - 1,
- sizeConverter.DataToScreenY(yValue + yMarginAbsolute), 2,
- sizeConverter.DataToScreenY(yValue - yMarginAbsolute) - sizeConverter.DataToScreenY(yValue + yMarginAbsolute));
+ this.sizeConverter.DataToScreenY(yValue + yMarginAbsolute), 2,
+ this.sizeConverter.DataToScreenY(yValue - yMarginAbsolute) - this.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!);
+ this.baseColorFromBrush(brush), normalization != 0 ? 1 : 0.6 * binBrushMaxAxis / this.sizeConverter.DataRanges[1] + 0.4, dataValue);
}
+ return 0;
}
- private createHorizontalBarChartBinPrimitives(bin: Bin, brush: Brush, binBrushMaxAxis: number, normalization: number, 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);
+ private createHorizontalBarChartBinPrimitives(bin: Bin, brush: Brush, binBrushMaxAxis: number, normalization: number): number {
+ let dataValue = this.histoOp.getValue(0, bin, this.histoResult, brush.brushIndex!);
+ if (dataValue != undefined) {
+ let [xFrom, xValue, xTo] = this.sizeConverter.DataToScreenNormalizedRange(dataValue, normalization, 0, binBrushMaxAxis);
+ let [yFrom, yTo] = this.sizeConverter.DataToScreenAxisRange(this._histoBox.VisualBinRanges, 1, bin);
- var marginResult = ModelHelpers.GetAggregateResult(bin, xMarginAggregateKey) as MarginAggregateResult;
- var xMarginAbsolute = sizeConverter.IsSmall || !marginResult ? 0 : marginResult.absolutMargin!;
-
- var marginRect = new PIXIRectangle(sizeConverter.DataToScreenX(xValue - xMarginAbsolute),
+ var xMarginAbsolute = this.sizeConverter.IsSmall ? 0 : this.getMargin(bin, brush, this.histoOp.X);
+ var marginRect = new PIXIRectangle(this.sizeConverter.DataToScreenX(xValue - xMarginAbsolute),
yTo + (yFrom - yTo) / 2.0 - 1,
- sizeConverter.DataToScreenX(xValue + xMarginAbsolute) - sizeConverter.DataToScreenX(xValue - xMarginAbsolute),
+ this.sizeConverter.DataToScreenX(xValue + xMarginAbsolute) - this.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!);
+ this.baseColorFromBrush(brush), normalization != 1 ? 1 : 0.6 * binBrushMaxAxis / this.sizeConverter.DataRanges[0] + 0.4, dataValue);
}
+ return 0;
+ }
+
+
+ private getMargin(bin: Bin, brush: Brush, axis: AttributeTransformationModel) {
+ var marginParams = new MarginAggregateParameters();
+ marginParams.aggregateFunction = axis.AggregateFunction;
+ var marginAggregateKey = ModelHelpers.CreateAggregateKey(axis, this.histoResult, brush.brushIndex!, marginParams);
+ var marginResult = ModelHelpers.GetAggregateResult(bin, marginAggregateKey) as MarginAggregateResult;
+ return !marginResult ? 0 : marginResult.absolutMargin!;
}
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),
+ Rect: new PIXIRectangle(xFrom, yTo, xTo - xFrom, yFrom - yTo),
MarginRect: marginRect,
MarginPercentage: marginPercentage,
BrushIndex: brush.brushIndex,
@@ -350,24 +279,18 @@ export class HistogramBinPrimitiveCollection {
}
private baseColorFromBrush(brush: Brush): number {
- var baseColor: number = StyleConstants.HIGHLIGHT_COLOR;
if (brush.brushIndex == ModelHelpers.RestBrushIndex(this.histoResult)) {
- baseColor = StyleConstants.HIGHLIGHT_COLOR;
+ return StyleConstants.HIGHLIGHT_COLOR;
}
else if (brush.brushIndex == ModelHelpers.OverlapBrushIndex(this.histoResult)) {
- baseColor = StyleConstants.OVERLAP_COLOR;
+ return StyleConstants.OVERLAP_COLOR;
}
else if (brush.brushIndex == ModelHelpers.AllBrushIndex(this.histoResult)) {
- baseColor = 0x00ff00;
+ return 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;
- }
+ else if (this.histoOp.BrushColors.length > 0) {
+ return this.histoOp.BrushColors[brush.brushIndex! % this.histoOp.BrushColors.length];
}
- return baseColor;
+ return StyleConstants.HIGHLIGHT_COLOR;
}
}
\ No newline at end of file
--
cgit v1.2.3-70-g09d2
From 1bd678851632bbbb302363574eb5e3e19dc343e9 Mon Sep 17 00:00:00 2001
From: bob
Date: Fri, 29 Mar 2019 13:18:35 -0400
Subject: reorganized and mostly working northstar histograms.
---
src/client/documents/Documents.ts | 13 +-
src/client/northstar/core/filter/FilterModel.ts | 2 +-
src/client/northstar/dash-fields/HistogramField.ts | 64 ++++
src/client/northstar/dash-nodes/HistogramBox.scss | 34 ++
src/client/northstar/dash-nodes/HistogramBox.tsx | 161 ++++++++++
.../dash-nodes/HistogramBoxPrimitives.scss | 26 ++
.../dash-nodes/HistogramBoxPrimitives.tsx | 341 +++++++++++++++++++++
.../dash-nodes/HistogramLabelPrimitives.scss | 13 +
.../dash-nodes/HistogramLabelPrimitives.tsx | 78 +++++
src/client/northstar/model/ModelHelpers.ts | 18 +-
.../model/binRanges/VisualBinRangeHelper.ts | 6 +-
src/client/northstar/operations/BaseOperation.ts | 4 +-
.../northstar/operations/HistogramOperation.ts | 13 +-
src/client/northstar/utils/SizeConverter.ts | 6 +-
src/client/views/Main.tsx | 39 +--
src/client/views/nodes/DocumentContentsView.tsx | 5 +-
src/client/views/nodes/DocumentView.tsx | 3 -
src/client/views/nodes/HistogramBox.scss | 22 --
src/client/views/nodes/HistogramBox.tsx | 105 -------
src/client/views/nodes/HistogramBoxPrimitives.scss | 25 --
src/client/views/nodes/HistogramBoxPrimitives.tsx | 336 --------------------
.../views/nodes/HistogramLabelPrimitives.scss | 12 -
.../views/nodes/HistogramLabelPrimitives.tsx | 78 -----
src/fields/HistogramField.ts | 59 ----
src/fields/KeyStore.ts | 1 -
src/server/ServerUtil.ts | 3 +-
.../authentication/models/current_user_utils.ts | 27 +-
27 files changed, 789 insertions(+), 705 deletions(-)
create mode 100644 src/client/northstar/dash-fields/HistogramField.ts
create mode 100644 src/client/northstar/dash-nodes/HistogramBox.scss
create mode 100644 src/client/northstar/dash-nodes/HistogramBox.tsx
create mode 100644 src/client/northstar/dash-nodes/HistogramBoxPrimitives.scss
create mode 100644 src/client/northstar/dash-nodes/HistogramBoxPrimitives.tsx
create mode 100644 src/client/northstar/dash-nodes/HistogramLabelPrimitives.scss
create mode 100644 src/client/northstar/dash-nodes/HistogramLabelPrimitives.tsx
delete mode 100644 src/client/views/nodes/HistogramBox.scss
delete mode 100644 src/client/views/nodes/HistogramBox.tsx
delete mode 100644 src/client/views/nodes/HistogramBoxPrimitives.scss
delete mode 100644 src/client/views/nodes/HistogramBoxPrimitives.tsx
delete mode 100644 src/client/views/nodes/HistogramLabelPrimitives.scss
delete mode 100644 src/client/views/nodes/HistogramLabelPrimitives.tsx
delete mode 100644 src/fields/HistogramField.ts
(limited to 'src/client/northstar/operations')
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 837dfe815..663ccae61 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -1,6 +1,6 @@
import { AudioField } from "../../fields/AudioField";
import { Document } from "../../fields/Document";
-import { Field, FieldWaiting } from "../../fields/Field";
+import { Field } from "../../fields/Field";
import { HtmlField } from "../../fields/HtmlField";
import { ImageField } from "../../fields/ImageField";
import { InkField, StrokeData } from "../../fields/InkField";
@@ -11,6 +11,9 @@ import { PDFField } from "../../fields/PDFField";
import { TextField } from "../../fields/TextField";
import { VideoField } from "../../fields/VideoField";
import { WebField } from "../../fields/WebField";
+import { HistogramField } from "../northstar/dash-fields/HistogramField";
+import { HistogramBox } from "../northstar/dash-nodes/HistogramBox";
+import { HistogramOperation } from "../northstar/operations/HistogramOperation";
import { Server } from "../Server";
import { CollectionPDFView } from "../views/collections/CollectionPDFView";
import { CollectionVideoView } from "../views/collections/CollectionVideoView";
@@ -22,10 +25,6 @@ import { KeyValueBox } from "../views/nodes/KeyValueBox";
import { PDFBox } from "../views/nodes/PDFBox";
import { VideoBox } from "../views/nodes/VideoBox";
import { WebBox } from "../views/nodes/WebBox";
-import { HistogramBox } from "../views/nodes/HistogramBox";
-import { FieldView } from "../views/nodes/FieldView";
-import { HistogramField } from "../../fields/HistogramField";
-import { HistogramOperation } from "../northstar/operations/HistogramOperation";
export interface DocumentOptions {
x?: number;
@@ -44,7 +43,6 @@ export interface DocumentOptions {
layoutKeys?: Key[];
viewType?: number;
backgroundColor?: string;
- northstarSchema?: string;
}
export namespace Documents {
@@ -88,7 +86,6 @@ export namespace Documents {
if (options.ink !== undefined) { doc.Set(KeyStore.Ink, new InkField(options.ink)); }
if (options.layout !== undefined) { doc.SetText(KeyStore.Layout, options.layout); }
if (options.layoutKeys !== undefined) { doc.Set(KeyStore.LayoutKeys, new ListField(options.layoutKeys)); }
- if (options.northstarSchema !== undefined) { doc.SetText(KeyStore.NorthstarSchema, options.northstarSchema); }
return doc;
}
@@ -126,7 +123,7 @@ export namespace Documents {
function GetHistogramPrototype(): Document {
if (!histoProto) {
histoProto = setupPrototypeOptions(histoProtoId, "HISTO PROTO", CollectionView.LayoutString("AnnotationsKey"),
- { x: 0, y: 0, width: 300, height: 300, layoutKeys: [KeyStore.Data, KeyStore.Annotations, KeyStore.Caption] });
+ { x: 0, y: 0, width: 300, height: 300, backgroundColor: "black", layoutKeys: [KeyStore.Data, KeyStore.Annotations, KeyStore.Caption] });
histoProto.SetText(KeyStore.BackgroundLayout, HistogramBox.LayoutString());
}
return histoProto;
diff --git a/src/client/northstar/core/filter/FilterModel.ts b/src/client/northstar/core/filter/FilterModel.ts
index bc7938947..aee99d2b6 100644
--- a/src/client/northstar/core/filter/FilterModel.ts
+++ b/src/client/northstar/core/filter/FilterModel.ts
@@ -2,10 +2,10 @@ import { ValueComparison } from "./ValueComparision";
import { Utils } from "../../utils/Utils";
import { IBaseFilterProvider } from "./IBaseFilterProvider";
import { FilterOperand } from "./FilterOperand";
-import { HistogramField } from "../../../../fields/HistogramField";
import { KeyStore } from "../../../../fields/KeyStore";
import { FieldWaiting } from "../../../../fields/Field";
import { Document } from "../../../../fields/Document";
+import { HistogramField } from "../../dash-fields/HistogramField";
export class FilterModel {
public ValueComparisons: ValueComparison[];
diff --git a/src/client/northstar/dash-fields/HistogramField.ts b/src/client/northstar/dash-fields/HistogramField.ts
new file mode 100644
index 000000000..00912c595
--- /dev/null
+++ b/src/client/northstar/dash-fields/HistogramField.ts
@@ -0,0 +1,64 @@
+import { BasicField } from "../../../fields/BasicField";
+import { Field, FieldId } from "../../../fields/Field";
+import { Types } from "../../../server/Message";
+import { HistogramOperation } from "../../../client/northstar/operations/HistogramOperation";
+import { action } from "mobx";
+import { AttributeTransformationModel } from "../../../client/northstar/core/attribute/AttributeTransformationModel";
+import { ColumnAttributeModel } from "../../../client/northstar/core/attribute/AttributeModel";
+import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils";
+import { ArrayUtil } from "../utils/ArrayUtil";
+import { Schema } from "../model/idea/idea";
+
+
+export class HistogramField extends BasicField {
+ constructor(data?: HistogramOperation, id?: FieldId, save: boolean = true) {
+ super(data ? data : HistogramOperation.Empty, save, id);
+ }
+
+ toString(): string {
+ return JSON.stringify(this.Data);
+ }
+
+ Copy(): Field {
+ return new HistogramField(this.Data);
+ }
+
+ ToScriptString(): string {
+ return `new HistogramField("${this.Data}")`;
+ }
+
+ ToJson(): { type: Types, data: string, _id: string } {
+ return {
+ type: Types.HistogramOp,
+ data: JSON.stringify(this.Data),
+ _id: this.Id
+ }
+ }
+
+ @action
+ static FromJson(id: string, data: any): HistogramField {
+ let jp = JSON.parse(data);
+ let X: AttributeTransformationModel | undefined;
+ let Y: AttributeTransformationModel | undefined;
+ let V: AttributeTransformationModel | undefined;
+
+ let schema = CurrentUserUtils.GetNorthstarSchema(jp.SchemaName);
+ if (schema) {
+ CurrentUserUtils.GetAllNorthstarColumnAttributes(schema).map(attr => {
+ if (attr.displayName == jp.X.AttributeModel.Attribute.DisplayName) {
+ X = new AttributeTransformationModel(new ColumnAttributeModel(attr), jp.X.AggregateFunction);
+ }
+ if (attr.displayName == jp.Y.AttributeModel.Attribute.DisplayName) {
+ Y = new AttributeTransformationModel(new ColumnAttributeModel(attr), jp.Y.AggregateFunction);
+ }
+ if (attr.displayName == jp.V.AttributeModel.Attribute.DisplayName) {
+ V = new AttributeTransformationModel(new ColumnAttributeModel(attr), jp.V.AggregateFunction);
+ }
+ });
+ if (X && Y && V) {
+ return new HistogramField(new HistogramOperation(jp.SchemaName, X, Y, V, jp.Normalization), id, false);
+ }
+ }
+ return new HistogramField(HistogramOperation.Empty, id, false);
+ }
+}
\ No newline at end of file
diff --git a/src/client/northstar/dash-nodes/HistogramBox.scss b/src/client/northstar/dash-nodes/HistogramBox.scss
new file mode 100644
index 000000000..b11840a65
--- /dev/null
+++ b/src/client/northstar/dash-nodes/HistogramBox.scss
@@ -0,0 +1,34 @@
+.histogrambox-container {
+ padding: 0vw;
+ position: absolute;
+ text-align: center;
+ width: 100%;
+ height: 100%;
+ background: black;
+ }
+ .histogrambox-xaxislabel {
+ position:absolute;
+ width:100%;
+ text-align: center;
+ bottom:0;
+ background: lightgray;
+ font-size: 14;
+ font-weight: bold;
+ }
+ .histogrambox-yaxislabel {
+ position:absolute;
+ height:100%;
+ width: 25px;
+ bottom:0;
+ background: lightgray;
+ }
+ .histogrambox-yaxislabel-text {
+ position:absolute;
+ transform-origin: left;
+ transform: rotate(-90deg);
+ text-align: center;
+ font-size: 14;
+ font-weight: bold;
+ bottom: calc(50% - 25px);
+ }
+
\ No newline at end of file
diff --git a/src/client/northstar/dash-nodes/HistogramBox.tsx b/src/client/northstar/dash-nodes/HistogramBox.tsx
new file mode 100644
index 000000000..9f8c2cfd0
--- /dev/null
+++ b/src/client/northstar/dash-nodes/HistogramBox.tsx
@@ -0,0 +1,161 @@
+import React = require("react")
+import { action, computed, observable, reaction, runInAction } from "mobx";
+import { observer } from "mobx-react";
+import Measure from "react-measure";
+import { Dictionary } from "typescript-collections";
+import { FieldWaiting, Opt } from "../../../fields/Field";
+import { KeyStore } from "../../../fields/KeyStore";
+import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils";
+import { FilterModel } from '../../northstar/core/filter/FilterModel';
+import { ChartType, VisualBinRange } from '../../northstar/model/binRanges/VisualBinRange';
+import { VisualBinRangeHelper } from "../../northstar/model/binRanges/VisualBinRangeHelper";
+import { AggregateBinRange, BinRange, DoubleValueAggregateResult, HistogramResult, Catalog } from "../../northstar/model/idea/idea";
+import { ModelHelpers } from "../../northstar/model/ModelHelpers";
+import { HistogramOperation } from "../../northstar/operations/HistogramOperation";
+import { PIXIRectangle } from "../../northstar/utils/MathUtil";
+import { SizeConverter } from "../../northstar/utils/SizeConverter";
+import { DragManager } from "../../util/DragManager";
+import { FieldView, FieldViewProps } from "../../views/nodes/FieldView";
+import { HistogramField } from "../dash-fields/HistogramField";
+import "../utils/Extensions"
+import "./HistogramBox.scss";
+import { HistogramBoxPrimitives } from './HistogramBoxPrimitives';
+import { HistogramLabelPrimitives } from "./HistogramLabelPrimitives";
+
+export interface HistogramPrimitivesProps {
+ HistoBox: HistogramBox;
+}
+
+@observer
+export class HistogramBox extends React.Component {
+ public static LayoutString(fieldStr: string = "DataKey") { return FieldView.LayoutString(HistogramBox, fieldStr) }
+ private _dropXRef = React.createRef();
+ private _dropYRef = React.createRef();
+ private _dropXDisposer?: DragManager.DragDropDisposer;
+ private _dropYDisposer?: DragManager.DragDropDisposer;
+
+ @observable public PanelWidth: number = 100;
+ @observable public PanelHeight: number = 100;
+ @observable public HistoOp: HistogramOperation = HistogramOperation.Empty;
+ @observable public VisualBinRanges: VisualBinRange[] = [];
+ @observable public ValueRange: number[] = [];
+ @observable public SizeConverter: SizeConverter = new SizeConverter();
+
+ @computed get createOperationParamsCache() { return this.HistoOp.CreateOperationParameters(); }
+ @computed get HistogramResult() { return this.HistoOp ? this.HistoOp.Result as HistogramResult : undefined; }
+ @computed get BinRanges() { return this.HistogramResult ? this.HistogramResult.binRanges : undefined; }
+ @computed get ChartType() {
+ return !this.BinRanges ? ChartType.SinglePoint : this.BinRanges[0] instanceof AggregateBinRange ?
+ (this.BinRanges[1] instanceof AggregateBinRange ? ChartType.SinglePoint : ChartType.HorizontalBar) :
+ this.BinRanges[1] instanceof AggregateBinRange ? ChartType.VerticalBar : ChartType.HeatMap;
+ }
+
+ constructor(props: FieldViewProps) {
+ super(props);
+ }
+
+ @action
+ dropX = (e: Event, de: DragManager.DropEvent) => {
+ if (de.data instanceof DragManager.DocumentDragData) {
+ let h = de.data.draggedDocument.GetT(KeyStore.Data, HistogramField);
+ if (h && h != FieldWaiting) {
+ this.HistoOp.X = h.Data.X;
+ }
+ e.stopPropagation();
+ e.preventDefault();
+ }
+ }
+ @action
+ dropY = (e: Event, de: DragManager.DropEvent) => {
+ if (de.data instanceof DragManager.DocumentDragData) {
+ let h = de.data.draggedDocument.GetT(KeyStore.Data, HistogramField);
+ if (h && h != FieldWaiting) {
+ this.HistoOp.Y = h.Data.X;
+ }
+ e.stopPropagation();
+ e.preventDefault();
+ }
+ }
+
+ componentDidMount() {
+ if (this._dropXRef.current) {
+ this._dropXDisposer = DragManager.MakeDropTarget(this._dropXRef.current, { handlers: { drop: this.dropX.bind(this) } });
+ }
+ if (this._dropYRef.current) {
+ this._dropYDisposer = DragManager.MakeDropTarget(this._dropYRef.current, { handlers: { drop: this.dropY.bind(this) } });
+ }
+ reaction(() => CurrentUserUtils.NorthstarDBCatalog, (catalog?: Catalog) => this.activateHistogramOperation(catalog), { fireImmediately: true });
+ reaction(() => [this.VisualBinRanges && this.VisualBinRanges.slice()], () => this.SizeConverter.SetVisualBinRanges(this.VisualBinRanges));
+ reaction(() => [this.PanelHeight, this.PanelWidth], () => this.SizeConverter.SetIsSmall(this.PanelWidth < 40 && this.PanelHeight < 40))
+ reaction(() => this.HistogramResult ? this.HistogramResult.binRanges : undefined,
+ (binRanges: BinRange[] | undefined) => {
+ if (binRanges) {
+ this.VisualBinRanges.splice(0, this.VisualBinRanges.length, ...binRanges.map((br, ind) =>
+ VisualBinRangeHelper.GetVisualBinRange(this.HistoOp.Schema!.distinctAttributeParameters, br, this.HistogramResult!, ind ? this.HistoOp.Y : this.HistoOp.X, this.ChartType)));
+
+ let valueAggregateKey = ModelHelpers.CreateAggregateKey(this.HistoOp.Schema!.distinctAttributeParameters, this.HistoOp.V, this.HistogramResult!, ModelHelpers.AllBrushIndex(this.HistogramResult!));
+ this.ValueRange = Object.values(this.HistogramResult!.bins!).reduce((prev, cur) => {
+ let value = ModelHelpers.GetAggregateResult(cur, valueAggregateKey) as DoubleValueAggregateResult;
+ return value && value.hasResult ? [Math.min(prev[0], value.result!), Math.max(prev[1], value.result!)] : prev;
+ }, [Number.MAX_VALUE, Number.MIN_VALUE]);
+ }
+ });
+ }
+
+ @action
+ xLabelPointerDown = (e: React.PointerEvent) => {
+
+ }
+
+ componentWillUnmount() {
+ if (this._dropXDisposer)
+ this._dropXDisposer();
+ if (this._dropYDisposer)
+ this._dropYDisposer();
+ }
+
+ activateHistogramOperation(catalog?: Catalog) {
+ if (catalog) {
+ this.props.doc.GetTAsync(this.props.fieldKey, HistogramField).then((histoOp: Opt) => runInAction(() => {
+ this.HistoOp = histoOp ? histoOp.Data : HistogramOperation.Empty;
+ if (this.HistoOp != HistogramOperation.Empty) {
+ reaction(() => this.props.doc.GetList(KeyStore.LinkedFromDocs, []), docs => this.HistoOp.Links.splice(0, this.HistoOp.Links.length, ...docs), { fireImmediately: true });
+ reaction(() => this.createOperationParamsCache, () => this.HistoOp.Update(), { fireImmediately: true });
+ }
+ }));
+ }
+ }
+ render() {
+ let labelY = this.HistoOp && this.HistoOp.Y ? this.HistoOp.Y.PresentedName : "<...>";
+ let labelX = this.HistoOp && this.HistoOp.X ? this.HistoOp.X.PresentedName : "<...>";
+ var h = this.props.isTopMost ? this.PanelHeight : this.props.doc.GetNumber(KeyStore.Height, 0);
+ var w = this.props.isTopMost ? this.PanelWidth : this.props.doc.GetNumber(KeyStore.Width, 0);
+ let loff = this.SizeConverter.LeftOffset;
+ let toff = this.SizeConverter.TopOffset;
+ let roff = this.SizeConverter.RightOffset;
+ let boff = this.SizeConverter.BottomOffset;
+ return (
+ runInAction(() => { this.PanelWidth = r.entry.width; this.PanelHeight = r.entry.height })}>
+ {({ measureRef }) =>
+
+
+
+ {labelY}
+
+
+
+
+
+
+
{labelX}
+
+ }
+
+ )
+ }
+}
+
diff --git a/src/client/northstar/dash-nodes/HistogramBoxPrimitives.scss b/src/client/northstar/dash-nodes/HistogramBoxPrimitives.scss
new file mode 100644
index 000000000..9d42219cc
--- /dev/null
+++ b/src/client/northstar/dash-nodes/HistogramBoxPrimitives.scss
@@ -0,0 +1,26 @@
+.histogramboxprimitives-border {
+ border: 3px;
+ border-style: solid;
+ border-color: white;
+ pointer-events: none;
+ position: absolute;
+}
+.histogramboxprimitives-bar {
+ position: absolute;
+ border: 1px;
+ border-style: solid;
+ border-color: #282828;
+ pointer-events: all;
+}
+
+.histogramboxprimitives-placer {
+ position: absolute;
+ pointer-events: none;
+ width: 100%;
+ height: 100%;
+}
+.histogramboxprimitives-line {
+ position: absolute;
+ background: darkGray;
+ opacity: 0.4;
+}
\ No newline at end of file
diff --git a/src/client/northstar/dash-nodes/HistogramBoxPrimitives.tsx b/src/client/northstar/dash-nodes/HistogramBoxPrimitives.tsx
new file mode 100644
index 000000000..d2f1be4fd
--- /dev/null
+++ b/src/client/northstar/dash-nodes/HistogramBoxPrimitives.tsx
@@ -0,0 +1,341 @@
+import React = require("react")
+import { computed, observable, runInAction } from "mobx";
+import { observer } from "mobx-react";
+import { Utils as DashUtils } from '../../../Utils';
+import { AttributeTransformationModel } from "../../northstar/core/attribute/AttributeTransformationModel";
+import { FilterModel } from "../../northstar/core/filter/FilterModel";
+import { ChartType } from '../../northstar/model/binRanges/VisualBinRange';
+import { AggregateFunction, Bin, Brush, HistogramResult, MarginAggregateParameters, MarginAggregateResult } from "../../northstar/model/idea/idea";
+import { ModelHelpers } from "../../northstar/model/ModelHelpers";
+import { ArrayUtil } from "../../northstar/utils/ArrayUtil";
+import { LABColor } from '../../northstar/utils/LABcolor';
+import { PIXIRectangle } from "../../northstar/utils/MathUtil";
+import { StyleConstants } from "../../northstar/utils/StyleContants";
+import { HistogramBox, HistogramPrimitivesProps } from "./HistogramBox";
+import "./HistogramBoxPrimitives.scss";
+
+
+@observer
+export class HistogramBoxPrimitives extends React.Component {
+ private get histoOp() { return this.props.HistoBox.HistoOp; }
+ private get renderDimension() { return this.props.HistoBox.SizeConverter.RenderDimension; }
+ @observable _selectedPrims: HistogramBinPrimitive[] = [];
+ @computed get xaxislines() { return this.renderGridLinesAndLabels(0); }
+ @computed get yaxislines() { return this.renderGridLinesAndLabels(1); }
+ @computed get selectedPrimitives() { return this._selectedPrims.map(bp => this.drawRect(bp.Rect, bp.BarAxis, undefined, "border")); }
+ @computed get binPrimitives() {
+ let histoResult = this.props.HistoBox.HistogramResult;
+ if (!histoResult || !histoResult.bins || !this.props.HistoBox.VisualBinRanges.length)
+ return (null);
+ let allBrushIndex = ModelHelpers.AllBrushIndex(histoResult);
+ return Object.keys(histoResult.bins).reduce((prims, key) => {
+ let drawPrims = new HistogramBinPrimitiveCollection(histoResult!.bins![key], this.props.HistoBox);
+
+ let toggle = this.getSelectionToggle(drawPrims.BinPrimitives, allBrushIndex,
+ ModelHelpers.GetBinFilterModel(histoResult!.bins![key], allBrushIndex, histoResult!, this.histoOp.X, this.histoOp.Y));
+ drawPrims.BinPrimitives.filter(bp => bp.DataValue && bp.BrushIndex !== allBrushIndex).map(bp =>
+ prims.push(...[{ r: bp.Rect, c: bp.Color }, { r: bp.MarginRect, c: StyleConstants.MARGIN_BARS_COLOR }].map(pair => this.drawRect(pair.r, bp.BarAxis, pair.c, "bar", toggle))));
+ return prims;
+ }, [] as JSX.Element[]);
+ }
+
+ private getSelectionToggle(binPrimitives: HistogramBinPrimitive[], allBrushIndex: number, filterModel: FilterModel) {
+ let allBrushPrim = ArrayUtil.FirstOrDefault(binPrimitives, bp => bp.BrushIndex == allBrushIndex);
+ return !allBrushPrim ? () => { } : () => runInAction(() => {
+ if (ArrayUtil.Contains(this.histoOp.FilterModels, filterModel)) {
+ this._selectedPrims.splice(this._selectedPrims.indexOf(allBrushPrim!), 1);
+ this.histoOp.RemoveFilterModels([filterModel]);
+ }
+ else {
+ this._selectedPrims.push(allBrushPrim!);
+ this.histoOp.AddFilterModels([filterModel]);
+ }
+ })
+ }
+
+ private renderGridLinesAndLabels(axis: number) {
+ if (!this.props.HistoBox.SizeConverter.Initialized)
+ return (null);
+ let labels = this.props.HistoBox.VisualBinRanges[axis].GetLabels();
+ return labels.reduce((prims, binLabel, i) => {
+ let r = this.props.HistoBox.SizeConverter.DataToScreenRange(binLabel.minValue!, binLabel.maxValue!, axis);
+ prims.push(this.drawLine(r.xFrom, r.yFrom, axis == 0 ? 0 : r.xTo - r.xFrom, axis == 0 ? r.yTo - r.yFrom : 0));
+ if (i == labels.length - 1)
+ prims.push(this.drawLine(axis == 0 ? r.xTo : r.xFrom, axis == 0 ? r.yFrom : r.yTo, axis == 0 ? 0 : r.xTo - r.xFrom, axis == 0 ? r.yTo - r.yFrom : 0));
+ return prims;
+ }, [] as JSX.Element[]);
+ }
+
+ drawEntity(xFrom: number, yFrom: number, entity: JSX.Element) {
+ let transXpercent = xFrom / this.renderDimension * 100;
+ let transYpercent = yFrom / this.renderDimension * 100;
+ return (
+ {entity}
+
);
+ }
+ drawLine(xFrom: number, yFrom: number, width: number, height: number) {
+ if (height < 0) {
+ yFrom += height;
+ height = -height;
+ }
+ if (width < 0) {
+ xFrom += width;
+ width = -width;
+ }
+ let trans2Xpercent = width == 0 ? `1px` : `${(xFrom + width) / this.renderDimension * 100}%`;
+ let trans2Ypercent = height == 0 ? `1px` : `${(yFrom + height) / this.renderDimension * 100}%`;
+ let line = ();
+ return this.drawEntity(xFrom, yFrom, line);
+ }
+
+ drawRect(r: PIXIRectangle, barAxis: number, color: number | undefined, classExt: string, tapHandler: () => void = () => { }) {
+ if (r.height < 0) {
+ r.y += r.height;
+ r.height = -r.height;
+ }
+ if (r.width < 0) {
+ r.x += r.width;
+ r.width = -r.width;
+ }
+ let widthPercent = r.width / this.renderDimension * 100;
+ let heightPercent = r.height / this.renderDimension * 100;
+ let rect = ( { if (e.button == 0) tapHandler() }}
+ style={{
+ borderBottomStyle: barAxis == 1 ? "none" : "solid",
+ borderLeftStyle: barAxis == 0 ? "none" : "solid",
+ width: `${widthPercent}%`,
+ height: `${heightPercent}%`,
+ background: color ? `${LABColor.RGBtoHexString(color)}` : ""
+ }}
+ />);
+ return this.drawEntity(r.x, r.y, rect);
+ }
+ render() {
+ return
+ {this.xaxislines}
+ {this.yaxislines}
+ {this.binPrimitives}
+ {this.selectedPrimitives}
+
+ }
+}
+
+class HistogramBinPrimitive {
+ constructor(init?: Partial
) {
+ Object.assign(this, init);
+ }
+ public DataValue: number = 0;
+ public Rect: PIXIRectangle = PIXIRectangle.EMPTY;
+ public MarginRect: PIXIRectangle = PIXIRectangle.EMPTY;
+ public MarginPercentage: number = 0;
+ public Color: number = StyleConstants.WARNING_COLOR;
+ public Opacity: number = 1;
+ public BrushIndex: number = 0;
+ public BarAxis: number = -1;
+}
+
+export class HistogramBinPrimitiveCollection {
+ private static TOLERANCE: number = 0.0001;
+
+ private _histoBox: HistogramBox;
+ private get histoOp() { return this._histoBox.HistoOp; }
+ private get histoResult() { return this.histoOp.Result as HistogramResult; }
+ private get sizeConverter() { return this._histoBox.SizeConverter!; }
+ public BinPrimitives: Array = new Array();
+ public HitGeom: PIXIRectangle = PIXIRectangle.EMPTY;
+
+ constructor(bin: Bin, histoBox: HistogramBox) {
+ this._histoBox = histoBox;
+ let brushing = this.setupBrushing(bin, this.histoOp.Normalization); // X= 0, Y = 1, V = 2
+
+ brushing.orderedBrushes.reduce((brushFactorSum, brush) => {
+ switch (histoBox.ChartType) {
+ case ChartType.VerticalBar: return this.createVerticalBarChartBinPrimitives(bin, brush, brushing.maxAxis, this.histoOp.Normalization);
+ case ChartType.HorizontalBar: return this.createHorizontalBarChartBinPrimitives(bin, brush, brushing.maxAxis, this.histoOp.Normalization);
+ case ChartType.SinglePoint: return this.createSinglePointChartBinPrimitives(bin, brush);
+ case ChartType.HeatMap: return this.createHeatmapBinPrimitives(bin, brush, brushFactorSum);
+ }
+ }, 0);
+
+ // adjust brush rects (stacking or not)
+ var allBrushIndex = ModelHelpers.AllBrushIndex(this.histoResult);
+ var filteredBinPrims = this.BinPrimitives.filter(b => b.BrushIndex != allBrushIndex && b.DataValue != 0.0);
+ filteredBinPrims.reduce((sum, fbp) => {
+ if (histoBox.ChartType == ChartType.VerticalBar) {
+ if (this.histoOp.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);
+ return sum + fbp.Rect.height;
+ }
+ if (this.histoOp.Y.AggregateFunction == AggregateFunction.Avg) {
+ var w = fbp.Rect.width / 2.0;
+ fbp.Rect = new PIXIRectangle(fbp.Rect.x + sum, fbp.Rect.y, fbp.Rect.width / filteredBinPrims.length, fbp.Rect.height);
+ fbp.MarginRect = new PIXIRectangle(fbp.MarginRect.x - w + sum + (fbp.Rect.width / 2.0), fbp.MarginRect.y, fbp.MarginRect.width, fbp.MarginRect.height);
+ return sum + fbp.Rect.width;
+ }
+ }
+ else if (histoBox.ChartType == ChartType.HorizontalBar) {
+ if (this.histoOp.X.AggregateFunction == AggregateFunction.Count) {
+ fbp.Rect = new PIXIRectangle(fbp.Rect.x + sum, fbp.Rect.y, fbp.Rect.width, fbp.Rect.height);
+ fbp.MarginRect = new PIXIRectangle(fbp.MarginRect.x + sum, fbp.MarginRect.y, fbp.MarginRect.width, fbp.MarginRect.height);
+ return sum + fbp.Rect.width;
+ }
+ if (this.histoOp.X.AggregateFunction == AggregateFunction.Avg) {
+ var h = fbp.Rect.height / 2.0;
+ fbp.Rect = new PIXIRectangle(fbp.Rect.x, fbp.Rect.y + sum, fbp.Rect.width, fbp.Rect.height / filteredBinPrims.length);
+ fbp.MarginRect = new PIXIRectangle(fbp.MarginRect.x, fbp.MarginRect.y - h + sum + (fbp.Rect.height / 2.0), fbp.MarginRect.width, fbp.MarginRect.height);
+ return sum + fbp.Rect.height;
+ }
+ }
+ return 0;
+ }, 0);
+ this.BinPrimitives = this.BinPrimitives.reverse();
+ var f = this.BinPrimitives.filter(b => b.BrushIndex == allBrushIndex);
+ this.HitGeom = f.length > 0 ? f[0].Rect : PIXIRectangle.EMPTY;
+ }
+ private setupBrushing(bin: Bin, normalization: number) {
+ var overlapBrushIndex = ModelHelpers.OverlapBrushIndex(this.histoResult);
+ var orderedBrushes = [this.histoResult.brushes![0], this.histoResult.brushes![overlapBrushIndex]];
+ this.histoResult.brushes!.map(brush => brush.brushIndex != 0 && brush.brushIndex != overlapBrushIndex && orderedBrushes.push(brush));
+ return {
+ orderedBrushes,
+ maxAxis: orderedBrushes.reduce((prev, Brush) => {
+ let aggResult = this.histoOp.getValue(normalization, bin, this.histoResult, Brush.brushIndex!);
+ return aggResult != undefined && aggResult > prev ? aggResult : prev;
+ }, Number.MIN_VALUE)
+ };
+ }
+ private createHeatmapBinPrimitives(bin: Bin, brush: Brush, brushFactorSum: number): number {
+
+ let unNormalizedValue = this.histoOp.getValue(2, bin, this.histoResult, brush.brushIndex!);
+ if (unNormalizedValue == undefined)
+ return brushFactorSum;
+
+ var normalizedValue = (unNormalizedValue - this._histoBox.ValueRange[0]) / (Math.abs((this._histoBox.ValueRange[1] - this._histoBox.ValueRange[0])) < HistogramBinPrimitiveCollection.TOLERANCE ?
+ unNormalizedValue : this._histoBox.ValueRange[1] - this._histoBox.ValueRange[0]);
+
+ let allUnNormalizedValue = this.histoOp.getValue(2, bin, this.histoResult, ModelHelpers.AllBrushIndex(this.histoResult))
+
+ // bcz: are these calls needed?
+ let [xFrom, xTo] = this.sizeConverter.DataToScreenXAxisRange(this._histoBox.VisualBinRanges, 0, bin);
+ let [yFrom, yTo] = this.sizeConverter.DataToScreenYAxisRange(this._histoBox.VisualBinRanges, 1, bin);
+
+ var returnBrushFactorSum = brushFactorSum;
+ if (allUnNormalizedValue != undefined) {
+ var brushFactor = (unNormalizedValue / allUnNormalizedValue);
+ returnBrushFactorSum += brushFactor;
+ returnBrushFactorSum = Math.min(returnBrushFactorSum, 1.0);
+
+ var tempRect = new PIXIRectangle(xFrom, yTo, xTo - xFrom, yFrom - yTo);
+ var ratio = (tempRect.width / tempRect.height);
+ var newHeight = Math.sqrt((1.0 / ratio) * ((tempRect.width * tempRect.height) * returnBrushFactorSum));
+ var newWidth = newHeight * ratio;
+
+ xFrom = (tempRect.x + (tempRect.width - newWidth) / 2.0);
+ yTo = (tempRect.y + (tempRect.height - newHeight) / 2.0);
+ xTo = (xFrom + newWidth);
+ yFrom = (yTo + newHeight);
+ }
+ var alpha = 0.0;
+ var color = this.baseColorFromBrush(brush);
+ var lerpColor = LABColor.Lerp(
+ LABColor.FromColor(StyleConstants.MIN_VALUE_COLOR),
+ LABColor.FromColor(color),
+ (alpha + Math.pow(normalizedValue, 1.0 / 3.0) * (1.0 - alpha)));
+ var dataColor = LABColor.ToColor(lerpColor);
+
+ this.createBinPrimitive(-1, brush, PIXIRectangle.EMPTY, 0, xFrom, xTo, yFrom, yTo, dataColor, 1, unNormalizedValue);
+ return returnBrushFactorSum;
+ }
+
+ private createSinglePointChartBinPrimitives(bin: Bin, brush: Brush): number {
+ let unNormalizedValue = this._histoBox.HistoOp.getValue(2, bin, this.histoResult, brush.brushIndex!);
+ if (unNormalizedValue != undefined) {
+ let [xFrom, xTo] = this.sizeConverter.DataToScreenPointRange(0, bin, ModelHelpers.CreateAggregateKey(this.histoOp.Schema!.distinctAttributeParameters, this.histoOp.X, this.histoResult, brush.brushIndex!));
+ let [yFrom, yTo] = this.sizeConverter.DataToScreenPointRange(1, bin, ModelHelpers.CreateAggregateKey(this.histoOp.Schema!.distinctAttributeParameters, this.histoOp.Y, this.histoResult, brush.brushIndex!));
+
+ if (xFrom != undefined && yFrom != undefined && xTo != undefined && yTo != undefined)
+ this.createBinPrimitive(-1, brush, PIXIRectangle.EMPTY, 0, xFrom, xTo, yFrom, yTo, this.baseColorFromBrush(brush), 1, unNormalizedValue);
+ }
+ return 0;
+ }
+
+ private createVerticalBarChartBinPrimitives(bin: Bin, brush: Brush, binBrushMaxAxis: number, normalization: number): number {
+ let dataValue = this.histoOp.getValue(1, bin, this.histoResult, brush.brushIndex!);
+ if (dataValue != undefined) {
+ let [yFrom, yValue, yTo] = this.sizeConverter.DataToScreenNormalizedRange(dataValue, normalization, 1, binBrushMaxAxis);
+ let [xFrom, xTo] = this.sizeConverter.DataToScreenXAxisRange(this._histoBox.VisualBinRanges, 0, bin);
+
+ var yMarginAbsolute = this.getMargin(bin, brush, this.histoOp.Y);
+ var marginRect = new PIXIRectangle(xFrom + (xTo - xFrom) / 2.0 - 1,
+ this.sizeConverter.DataToScreenY(yValue + yMarginAbsolute), 2,
+ this.sizeConverter.DataToScreenY(yValue - yMarginAbsolute) - this.sizeConverter.DataToScreenY(yValue + yMarginAbsolute));
+
+ this.createBinPrimitive(1, brush, marginRect, 0, xFrom, xTo, yFrom, yTo,
+ this.baseColorFromBrush(brush), normalization != 0 ? 1 : 0.6 * binBrushMaxAxis / this.sizeConverter.DataRanges[1] + 0.4, dataValue);
+ }
+ return 0;
+ }
+
+ private createHorizontalBarChartBinPrimitives(bin: Bin, brush: Brush, binBrushMaxAxis: number, normalization: number): number {
+ let dataValue = this.histoOp.getValue(0, bin, this.histoResult, brush.brushIndex!);
+ if (dataValue != undefined) {
+ let [xFrom, xValue, xTo] = this.sizeConverter.DataToScreenNormalizedRange(dataValue, normalization, 0, binBrushMaxAxis);
+ let [yFrom, yTo] = this.sizeConverter.DataToScreenYAxisRange(this._histoBox.VisualBinRanges, 1, bin);
+
+ var xMarginAbsolute = this.sizeConverter.IsSmall ? 0 : this.getMargin(bin, brush, this.histoOp.X);
+ var marginRect = new PIXIRectangle(this.sizeConverter.DataToScreenX(xValue - xMarginAbsolute),
+ yTo + (yFrom - yTo) / 2.0 - 1,
+ this.sizeConverter.DataToScreenX(xValue + xMarginAbsolute) - this.sizeConverter.DataToScreenX(xValue - xMarginAbsolute),
+ 2.0);
+
+ this.createBinPrimitive(0, brush, marginRect, 0, xFrom, xTo, yFrom, yTo,
+ this.baseColorFromBrush(brush), normalization != 1 ? 1 : 0.6 * binBrushMaxAxis / this.sizeConverter.DataRanges[0] + 0.4, dataValue);
+ }
+ return 0;
+ }
+
+
+ private getMargin(bin: Bin, brush: Brush, axis: AttributeTransformationModel) {
+ var marginParams = new MarginAggregateParameters();
+ marginParams.aggregateFunction = axis.AggregateFunction;
+ var marginAggregateKey = ModelHelpers.CreateAggregateKey(this.histoOp.Schema!.distinctAttributeParameters, axis, this.histoResult, brush.brushIndex!, marginParams);
+ var marginResult = ModelHelpers.GetAggregateResult(bin, marginAggregateKey) as MarginAggregateResult;
+ return !marginResult ? 0 : marginResult.absolutMargin!;
+ }
+
+ private createBinPrimitive(barAxis: number, brush: Brush, marginRect: PIXIRectangle,
+ marginPercentage: number, xFrom: number, xTo: number, yFrom: number, yTo: number, color: number, opacity: number, dataValue: number) {
+ var binPrimitive = new HistogramBinPrimitive(
+ {
+ Rect: new PIXIRectangle(xFrom, yTo, xTo - xFrom, yFrom - yTo),
+ MarginRect: marginRect,
+ MarginPercentage: marginPercentage,
+ BrushIndex: brush.brushIndex,
+ Color: color,
+ Opacity: opacity,
+ DataValue: dataValue,
+ BarAxis: barAxis
+ });
+ this.BinPrimitives.push(binPrimitive);
+ }
+
+ private baseColorFromBrush(brush: Brush): number {
+ if (brush.brushIndex == ModelHelpers.RestBrushIndex(this.histoResult)) {
+ return StyleConstants.HIGHLIGHT_COLOR;
+ }
+ else if (brush.brushIndex == ModelHelpers.OverlapBrushIndex(this.histoResult)) {
+ return StyleConstants.OVERLAP_COLOR;
+ }
+ else if (brush.brushIndex == ModelHelpers.AllBrushIndex(this.histoResult)) {
+ return 0x00ff00;
+ }
+ else if (this.histoOp.BrushColors.length > 0) {
+ return this.histoOp.BrushColors[brush.brushIndex! % this.histoOp.BrushColors.length];
+ }
+ return StyleConstants.HIGHLIGHT_COLOR;
+ }
+}
\ No newline at end of file
diff --git a/src/client/northstar/dash-nodes/HistogramLabelPrimitives.scss b/src/client/northstar/dash-nodes/HistogramLabelPrimitives.scss
new file mode 100644
index 000000000..304d33771
--- /dev/null
+++ b/src/client/northstar/dash-nodes/HistogramLabelPrimitives.scss
@@ -0,0 +1,13 @@
+
+ .histogramLabelPrimitives-gridlabel {
+ position:absolute;
+ transform-origin: left top;
+ font-size: 11;
+ color:white;
+ }
+ .histogramLabelPrimitives-placer {
+ position:absolute;
+ width:100%;
+ height:100%;
+ pointer-events: none;
+ }
\ No newline at end of file
diff --git a/src/client/northstar/dash-nodes/HistogramLabelPrimitives.tsx b/src/client/northstar/dash-nodes/HistogramLabelPrimitives.tsx
new file mode 100644
index 000000000..45b23874d
--- /dev/null
+++ b/src/client/northstar/dash-nodes/HistogramLabelPrimitives.tsx
@@ -0,0 +1,78 @@
+import React = require("react")
+import { action, computed, reaction } from "mobx";
+import { observer } from "mobx-react";
+import { Utils as DashUtils } from '../../../Utils';
+import { NominalVisualBinRange } from "../model/binRanges/NominalVisualBinRange";
+import "../utils/Extensions";
+import { StyleConstants } from "../utils/StyleContants";
+import { HistogramBox, HistogramPrimitivesProps } from "./HistogramBox";
+import "./HistogramLabelPrimitives.scss";
+
+@observer
+export class HistogramLabelPrimitives extends React.Component {
+ componentDidMount() {
+ reaction(() => [this.props.HistoBox.PanelWidth, this.props.HistoBox.SizeConverter.LeftOffset, this.props.HistoBox.VisualBinRanges.length],
+ (fields) => HistogramLabelPrimitives.computeLabelAngle(fields[0] as number, fields[1] as number, this.props.HistoBox), { fireImmediately: true });
+ }
+
+ @action
+ static computeLabelAngle(panelWidth: number, leftOffset: number, histoBox: HistogramBox) {
+ const textWidth = 30;
+ if (panelWidth > 0 && histoBox.VisualBinRanges.length && histoBox.VisualBinRanges[0] instanceof NominalVisualBinRange) {
+ let space = (panelWidth - leftOffset * 2) / histoBox.VisualBinRanges[0].GetBins().length;
+ histoBox.SizeConverter.SetLabelAngle(Math.min(Math.PI / 2, Math.max(Math.PI / 6, textWidth / space * Math.PI / 2)));
+ } else if (histoBox.SizeConverter.LabelAngle) {
+ histoBox.SizeConverter.SetLabelAngle(0);
+ }
+ }
+ @computed get xaxislines() { return this.renderGridLinesAndLabels(0); }
+ @computed get yaxislines() { return this.renderGridLinesAndLabels(1); }
+
+ private renderGridLinesAndLabels(axis: number) {
+ let sc = this.props.HistoBox.SizeConverter;
+ let vb = this.props.HistoBox.VisualBinRanges;
+ if (!vb.length || !sc.Initialized)
+ return (null);
+ let dim = (axis == 0 ? this.props.HistoBox.PanelWidth : this.props.HistoBox.PanelHeight) / ((axis == 0 && vb[axis] instanceof NominalVisualBinRange) ?
+ (12 + 5) : // (FontStyles.AxisLabel.fontSize + 5)));
+ sc.MaxLabelSizes[axis].coords[axis] + 5);
+
+ let labels = vb[axis].GetLabels();
+ return labels.reduce((prims, binLabel, i) => {
+ let r = sc.DataToScreenRange(binLabel.minValue!, binLabel.maxValue!, axis);
+ if (i % Math.ceil(labels.length / dim) === 0 && binLabel.label) {
+ const label = binLabel.label.Truncate(StyleConstants.MAX_CHAR_FOR_HISTOGRAM_LABELS, "...");
+ const textHeight = 14; const textWidth = 30;
+ let xStart = (axis === 0 ? r.xFrom + (r.xTo - r.xFrom) / 2.0 : r.xFrom - 10 - textWidth);
+ let yStart = (axis === 1 ? r.yFrom - textHeight / 2 : r.yFrom);
+
+ if (axis == 0 && vb[axis] instanceof NominalVisualBinRange) {
+ let space = (r.xTo - r.xFrom) / sc.RenderDimension * this.props.HistoBox.PanelWidth;
+ xStart += Math.max(textWidth / 2, (1 - textWidth / space) * textWidth / 2) - textHeight / 2;
+ }
+
+ let xPercent = axis == 1 ? `${xStart}px` : `${xStart / sc.RenderDimension * 100}%`
+ let yPercent = axis == 0 ? `${this.props.HistoBox.PanelHeight - sc.BottomOffset - textHeight}px` : `${yStart / sc.RenderDimension * 100}%`
+
+ prims.push(
+
+ )
+ }
+ return prims;
+ }, [] as JSX.Element[]);
+ }
+
+ render() {
+ let xaxislines = this.xaxislines;
+ let yaxislines = this.yaxislines;
+ return
+ {xaxislines}
+ {yaxislines}
+
+ }
+
+}
\ No newline at end of file
diff --git a/src/client/northstar/model/ModelHelpers.ts b/src/client/northstar/model/ModelHelpers.ts
index 8de0bd260..d0711fb69 100644
--- a/src/client/northstar/model/ModelHelpers.ts
+++ b/src/client/northstar/model/ModelHelpers.ts
@@ -13,11 +13,11 @@ import { CurrentUserUtils } from "../../../server/authentication/models/current_
export class ModelHelpers {
- public static CreateAggregateKey(atm: AttributeTransformationModel, histogramResult: HistogramResult,
+ public static CreateAggregateKey(distinctAttributeParameters: AttributeParameters | undefined, atm: AttributeTransformationModel, histogramResult: HistogramResult,
brushIndex: number, aggParameters?: SingleDimensionAggregateParameters): AggregateKey {
{
if (aggParameters == undefined) {
- aggParameters = ModelHelpers.GetAggregateParameter(atm);
+ aggParameters = ModelHelpers.GetAggregateParameter(distinctAttributeParameters, atm);
}
else {
aggParameters.attributeParameters = ModelHelpers.GetAttributeParameters(atm.AttributeModel);
@@ -34,40 +34,40 @@ export class ModelHelpers {
return ArrayUtil.IndexOfWithEqual(histogramResult.aggregateParameters!, aggParameters);
}
- public static GetAggregateParameter(atm: AttributeTransformationModel): AggregateParameters | undefined {
+ public static GetAggregateParameter(distinctAttributeParameters: AttributeParameters | undefined, atm: AttributeTransformationModel): AggregateParameters | undefined {
var aggParam: AggregateParameters | undefined;
if (atm.AggregateFunction === AggregateFunction.Avg) {
var avg = new AverageAggregateParameters();
avg.attributeParameters = ModelHelpers.GetAttributeParameters(atm.AttributeModel);
- avg.distinctAttributeParameters = CurrentUserUtils.ActiveSchema!.distinctAttributeParameters;
+ avg.distinctAttributeParameters = distinctAttributeParameters;
aggParam = avg;
}
else if (atm.AggregateFunction === AggregateFunction.Count) {
var cnt = new CountAggregateParameters();
cnt.attributeParameters = ModelHelpers.GetAttributeParameters(atm.AttributeModel);
- cnt.distinctAttributeParameters = CurrentUserUtils.ActiveSchema!.distinctAttributeParameters;
+ cnt.distinctAttributeParameters = distinctAttributeParameters;
aggParam = cnt;
}
else if (atm.AggregateFunction === AggregateFunction.Sum) {
var sum = new SumAggregateParameters();
sum.attributeParameters = ModelHelpers.GetAttributeParameters(atm.AttributeModel);
- sum.distinctAttributeParameters = CurrentUserUtils.ActiveSchema!.distinctAttributeParameters;
+ sum.distinctAttributeParameters = distinctAttributeParameters;
aggParam = sum;
}
return aggParam;
}
- public static GetAggregateParametersWithMargins(atms: Array): Array {
+ public static GetAggregateParametersWithMargins(distinctAttributeParameters: AttributeParameters | undefined, atms: Array): Array {
var aggregateParameters = new Array();
atms.forEach(agg => {
- var aggParams = ModelHelpers.GetAggregateParameter(agg);
+ var aggParams = ModelHelpers.GetAggregateParameter(distinctAttributeParameters, agg);
if (aggParams) {
aggregateParameters.push(aggParams);
var margin = new MarginAggregateParameters()
margin.aggregateFunction = agg.AggregateFunction;
margin.attributeParameters = ModelHelpers.GetAttributeParameters(agg.AttributeModel);
- margin.distinctAttributeParameters = CurrentUserUtils.ActiveSchema!.distinctAttributeParameters;
+ margin.distinctAttributeParameters = distinctAttributeParameters;
aggregateParameters.push(margin);
}
});
diff --git a/src/client/northstar/model/binRanges/VisualBinRangeHelper.ts b/src/client/northstar/model/binRanges/VisualBinRangeHelper.ts
index 9eae39800..53d585bb4 100644
--- a/src/client/northstar/model/binRanges/VisualBinRangeHelper.ts
+++ b/src/client/northstar/model/binRanges/VisualBinRangeHelper.ts
@@ -1,4 +1,4 @@
-import { BinRange, NominalBinRange, QuantitativeBinRange, Exception, AlphabeticBinRange, DateTimeBinRange, AggregateBinRange, DoubleValueAggregateResult, HistogramResult } from "../idea/idea";
+import { BinRange, NominalBinRange, QuantitativeBinRange, Exception, AlphabeticBinRange, DateTimeBinRange, AggregateBinRange, DoubleValueAggregateResult, HistogramResult, AttributeParameters } from "../idea/idea";
import { VisualBinRange, ChartType } from "./VisualBinRange";
import { NominalVisualBinRange } from "./NominalVisualBinRange";
import { QuantitativeVisualBinRange } from "./QuantitativeVisualBinRange";
@@ -30,13 +30,13 @@ export class VisualBinRangeHelper {
throw new Exception()
}
- public static GetVisualBinRange(dataBinRange: BinRange, histoResult: HistogramResult, attr: AttributeTransformationModel, chartType: ChartType): VisualBinRange {
+ public static GetVisualBinRange(distinctAttributeParameters: AttributeParameters | undefined, dataBinRange: BinRange, histoResult: HistogramResult, attr: AttributeTransformationModel, chartType: ChartType): VisualBinRange {
if (!(dataBinRange instanceof AggregateBinRange)) {
return VisualBinRangeHelper.GetNonAggregateVisualBinRange(dataBinRange);
}
else {
- var aggregateKey = ModelHelpers.CreateAggregateKey(attr, histoResult, ModelHelpers.AllBrushIndex(histoResult));
+ var aggregateKey = ModelHelpers.CreateAggregateKey(distinctAttributeParameters, attr, histoResult, ModelHelpers.AllBrushIndex(histoResult));
var minValue = Number.MAX_VALUE;
var maxValue = Number.MIN_VALUE;
for (var b = 0; b < histoResult.brushes!.length; b++) {
diff --git a/src/client/northstar/operations/BaseOperation.ts b/src/client/northstar/operations/BaseOperation.ts
index 7db6fcb91..94e0849af 100644
--- a/src/client/northstar/operations/BaseOperation.ts
+++ b/src/client/northstar/operations/BaseOperation.ts
@@ -10,9 +10,9 @@ export abstract class BaseOperation {
@observable public Error: string = "";
@observable public OverridingFilters: FilterModel[] = [];
- @observable public Result: Result | undefined;
+ @observable public Result?: Result = undefined;
@observable public ComputationStarted: boolean = false;
- public OperationReference: OperationReference | undefined = undefined;
+ public OperationReference?: OperationReference = undefined;
private static _nextId = 0;
public RequestSalt: string = "";
diff --git a/src/client/northstar/operations/HistogramOperation.ts b/src/client/northstar/operations/HistogramOperation.ts
index 6c7288d42..8a0f648f6 100644
--- a/src/client/northstar/operations/HistogramOperation.ts
+++ b/src/client/northstar/operations/HistogramOperation.ts
@@ -27,6 +27,8 @@ export class HistogramOperation extends BaseOperation implements IBaseFilterCons
@observable public V: AttributeTransformationModel;
@observable public BrusherModels: BrushLinkModel[] = [];
@observable public BrushableModels: BrushLinkModel[] = [];
+ @observable public SchemaName: string;
+ @computed public get Schema() { return CurrentUserUtils.GetNorthstarSchema(this.SchemaName); }
@action
public AddFilterModels(filterModels: FilterModel[]): void {
@@ -38,23 +40,24 @@ export class HistogramOperation extends BaseOperation implements IBaseFilterCons
}
public getValue(axis: number, bin: Bin, result: HistogramResult, brushIndex: number) {
- var aggregateKey = ModelHelpers.CreateAggregateKey(axis == 0 ? this.X : axis == 1 ? this.Y : this.V, result, brushIndex);
+ var aggregateKey = ModelHelpers.CreateAggregateKey(this.Schema!.distinctAttributeParameters, axis == 0 ? this.X : axis == 1 ? this.Y : this.V, result, brushIndex);
let dataValue = ModelHelpers.GetAggregateResult(bin, aggregateKey) as DoubleValueAggregateResult;
return dataValue != null && dataValue.hasResult ? dataValue.result : undefined;
}
- public static Empty = new HistogramOperation(new AttributeTransformationModel(new ColumnAttributeModel(new Attribute())), new AttributeTransformationModel(new ColumnAttributeModel(new Attribute())), new AttributeTransformationModel(new ColumnAttributeModel(new Attribute())));
+ public static Empty = new HistogramOperation("-empty schema-", new AttributeTransformationModel(new ColumnAttributeModel(new Attribute())), new AttributeTransformationModel(new ColumnAttributeModel(new Attribute())), new AttributeTransformationModel(new ColumnAttributeModel(new Attribute())));
Equals(other: Object): boolean {
throw new Error("Method not implemented.");
}
- constructor(x: AttributeTransformationModel, y: AttributeTransformationModel, v: AttributeTransformationModel, normalized?: number) {
+ constructor(schemaName: string, x: AttributeTransformationModel, y: AttributeTransformationModel, v: AttributeTransformationModel, normalized?: number) {
super();
this.X = x;
this.Y = y;
this.V = v;
this.Normalization = normalized ? normalized : -1;
+ this.SchemaName = schemaName;
}
@computed
@@ -93,7 +96,7 @@ export class HistogramOperation extends BaseOperation implements IBaseFilterCons
allAttributes = ArrayUtil.Distinct(allAttributes.filter(a => a.AggregateFunction !== AggregateFunction.None));
let numericDataTypes = [DataType.Int, DataType.Double, DataType.Float];
- let perBinAggregateParameters: AggregateParameters[] = ModelHelpers.GetAggregateParametersWithMargins(allAttributes);
+ let perBinAggregateParameters: AggregateParameters[] = ModelHelpers.GetAggregateParametersWithMargins(this.Schema!.distinctAttributeParameters, allAttributes);
let globalAggregateParameters: AggregateParameters[] = [];
[histoX, histoY]
.filter(a => a.AggregateFunction === AggregateFunction.None && ArrayUtil.Contains(numericDataTypes, a.AttributeModel.DataType))
@@ -112,7 +115,7 @@ export class HistogramOperation extends BaseOperation implements IBaseFilterCons
let [perBinAggregateParameters, globalAggregateParameters] = this.GetAggregateParameters(this.X, this.Y, this.V);
return new HistogramOperationParameters({
enableBrushComputation: true,
- adapterName: CurrentUserUtils.ActiveSchema!.displayName,
+ adapterName: this.SchemaName,
filter: this.FilterString,
brushes: this.BrushString,
binningParameters: [ModelHelpers.GetBinningParameters(this.X, SETTINGS_X_BINS, this.QRange ? this.QRange.minValue : undefined, this.QRange ? this.QRange.maxValue : undefined),
diff --git a/src/client/northstar/utils/SizeConverter.ts b/src/client/northstar/utils/SizeConverter.ts
index ffd162a83..30627dfd5 100644
--- a/src/client/northstar/utils/SizeConverter.ts
+++ b/src/client/northstar/utils/SizeConverter.ts
@@ -68,10 +68,14 @@ export class SizeConverter {
return [undefined, undefined];
}
- public DataToScreenAxisRange(visualBinRanges: VisualBinRange[], index: number, bin: Bin) {
+ public DataToScreenXAxisRange(visualBinRanges: VisualBinRange[], index: number, bin: Bin) {
var value = visualBinRanges[0].GetValueFromIndex(bin.binIndex!.indices![index]);
return [this.DataToScreenX(value), this.DataToScreenX(visualBinRanges[index].AddStep(value))]
}
+ public DataToScreenYAxisRange(visualBinRanges: VisualBinRange[], index: number, bin: Bin) {
+ var value = visualBinRanges[1].GetValueFromIndex(bin.binIndex!.indices![index]);
+ return [this.DataToScreenY(value), this.DataToScreenY(visualBinRanges[index].AddStep(value))]
+ }
public DataToScreenX(x: number): number {
return ((x - this.DataMins[0]) / this.DataRanges[0]) * this.RenderDimension;
diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx
index 09778ac77..2f20b102c 100644
--- a/src/client/views/Main.tsx
+++ b/src/client/views/Main.tsx
@@ -58,7 +58,7 @@ export class Main extends React.Component {
@observable private mainfreeform?: Document;
@observable public pwidth: number = 0;
@observable public pheight: number = 0;
- private _northstarColumns: Document[] = [];
+ private _northstarSchemas: Document[] = [];
@computed private get mainContainer(): Document | undefined {
let doc = this.userDocument.GetT(KeyStore.ActiveWorkspace, Document);
@@ -245,7 +245,7 @@ export class Main extends React.Component {
let addTextNode = action(() => Documents.TextDocument({ width: 200, height: 200, title: "a text note" }))
let addColNode = action(() => Documents.FreeformDocument([], { width: 200, height: 200, title: "a freeform collection" }));
let addSchemaNode = action(() => Documents.SchemaDocument([], { width: 200, height: 200, title: "a schema collection" }));
- let addTreeNode = action(() => Documents.TreeDocument(this._northstarColumns, { width: 200, height: 200, title: "a tree collection" }));
+ let addTreeNode = action(() => Documents.TreeDocument(this._northstarSchemas, { width: 100, height: 400, title: "northstar schemas" }));
let addVideoNode = action(() => Documents.VideoDocument(videourl, { width: 200, height: 200, title: "video node" }));
let addPDFNode = action(() => Documents.PdfDocument(pdfurl, { width: 200, height: 200, title: "a schema collection" }));
let addImageNode = action(() => Documents.ImageDocument(imgurl, { width: 200, height: 200, title: "an image of a cat" }));
@@ -334,24 +334,27 @@ export class Main extends React.Component {
// --------------- Northstar hooks ------------- /
@action SetNorthstarCatalog(ctlog: Catalog) {
+ CurrentUserUtils.NorthstarDBCatalog = ctlog;
if (ctlog && ctlog.schemas) {
- CurrentUserUtils.ActiveSchema = ArrayUtil.FirstOrDefault(ctlog.schemas!, (s: Schema) => s.displayName === "mimic");
- CurrentUserUtils.GetAllNorthstarColumnAttributes().map(attr => {
- Server.GetField(attr.displayName!, action((field: Opt) => {
- if (field instanceof Document) {
- this._northstarColumns.push(field);
- } else {
- var atmod = new ColumnAttributeModel(attr);
- let histoOp = new HistogramOperation(
- new AttributeTransformationModel(atmod, AggregateFunction.None),
- new AttributeTransformationModel(atmod, AggregateFunction.Count),
- new AttributeTransformationModel(atmod, AggregateFunction.Count));
- this._northstarColumns.push(Documents.HistogramDocument(histoOp, { width: 200, height: 200, title: attr.displayName!, northstarSchema: CurrentUserUtils.ActiveSchema!.displayName! }, attr.displayName!));
- }
- }));
+ this._northstarSchemas = ctlog.schemas.map(schema => {
+ let schemaDoc = Documents.TreeDocument([], { width: 50, height: 100, title: schema.displayName! });
+ let schemaDocuments = schemaDoc.GetList(KeyStore.Data, [] as Document[]);
+ CurrentUserUtils.GetAllNorthstarColumnAttributes(schema).map(attr => {
+ Server.GetField(attr.displayName!, action((field: Opt) => {
+ if (field instanceof Document) {
+ schemaDocuments.push(field);
+ } else {
+ var atmod = new ColumnAttributeModel(attr);
+ let histoOp = new HistogramOperation(schema!.displayName!,
+ new AttributeTransformationModel(atmod, AggregateFunction.None),
+ new AttributeTransformationModel(atmod, AggregateFunction.Count),
+ new AttributeTransformationModel(atmod, AggregateFunction.Count));
+ schemaDocuments.push(Documents.HistogramDocument(histoOp, { width: 200, height: 200, title: attr.displayName! }, attr.displayName!));
+ }
+ }));
+ });
+ return schemaDoc;
})
- console.log("Activating schema " + CurrentUserUtils.ActiveSchema!.displayName!)
- CurrentUserUtils.ActiveSchemaName = CurrentUserUtils.ActiveSchema!.displayName!;
}
}
async initializeNorthstar(): Promise {
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index b54744337..77551649c 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -19,8 +19,7 @@ import { KeyValueBox } from "./KeyValueBox";
import { PDFBox } from "./PDFBox";
import { VideoBox } from "./VideoBox";
import { WebBox } from "./WebBox";
-import { HistogramBox } from "./HistogramBox";
-import { HistogramBoxPrimitives } from "./HistogramBoxPrimitives";
+import { HistogramBox } from "../../northstar/dash-nodes/HistogramBox";
import React = require("react");
const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this?
@@ -54,7 +53,7 @@ export class DocumentContentsView extends React.ComponentError loading layout keys;
}
return {
}
private dropDisposer?: DragManager.DragDropDisposer;
- protected createDropTarget = (ele: HTMLDivElement) => {
-
- }
componentDidMount() {
if (this._mainCont.current) {
diff --git a/src/client/views/nodes/HistogramBox.scss b/src/client/views/nodes/HistogramBox.scss
deleted file mode 100644
index 2660b1b75..000000000
--- a/src/client/views/nodes/HistogramBox.scss
+++ /dev/null
@@ -1,22 +0,0 @@
-.histogrambox-container {
- padding: 0vw;
- position: absolute;
- text-align: center;
- width: 100%;
- height: 100%;
- }
- .histogrambox-xaxislabel {
- position:absolute;
- width:100%;
- text-align: center;
- bottom:0;
- font-size: 14;
- font-weight: bold;
- }
-
- .histogrambox-container {
- position:absolute;
- width:100%;
- height: 100%;
- }
-
\ No newline at end of file
diff --git a/src/client/views/nodes/HistogramBox.tsx b/src/client/views/nodes/HistogramBox.tsx
deleted file mode 100644
index 3307925a2..000000000
--- a/src/client/views/nodes/HistogramBox.tsx
+++ /dev/null
@@ -1,105 +0,0 @@
-import React = require("react")
-import { computed, observable, reaction, runInAction } from "mobx";
-import { observer } from "mobx-react";
-import Measure from "react-measure";
-import { Dictionary } from "typescript-collections";
-import { Opt } from "../../../fields/Field";
-import { HistogramField } from "../../../fields/HistogramField";
-import { KeyStore } from "../../../fields/KeyStore";
-import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils";
-import { FilterModel } from '../../northstar/core/filter/FilterModel';
-import { ChartType, VisualBinRange } from '../../northstar/model/binRanges/VisualBinRange';
-import { VisualBinRangeHelper } from "../../northstar/model/binRanges/VisualBinRangeHelper";
-import { AggregateBinRange, BinRange, DoubleValueAggregateResult, HistogramResult } from "../../northstar/model/idea/idea";
-import { ModelHelpers } from "../../northstar/model/ModelHelpers";
-import { HistogramOperation } from "../../northstar/operations/HistogramOperation";
-import { PIXIRectangle } from "../../northstar/utils/MathUtil";
-import { SizeConverter } from "../../northstar/utils/SizeConverter";
-import "./../../northstar/utils/Extensions";
-import { FieldView, FieldViewProps } from './FieldView';
-import "./HistogramBox.scss";
-import { HistogramBoxPrimitives } from './HistogramBoxPrimitives';
-import { HistogramLabelPrimitives } from "./HistogramLabelPrimitives";
-
-export interface HistogramPrimitivesProps {
- HistoBox: HistogramBox;
-}
-
-@observer
-export class HistogramBox extends React.Component {
- public static LayoutString(fieldStr: string = "DataKey") { return FieldView.LayoutString(HistogramBox, fieldStr) }
- public HitTargets: Dictionary = new Dictionary();
-
- @observable public PanelWidth: number = 100;
- @observable public PanelHeight: number = 100;
- @observable public HistoOp?: HistogramOperation;
- @observable public VisualBinRanges: VisualBinRange[] = [];
- @observable public ValueRange: number[] = [];
- @observable public SizeConverter: SizeConverter = new SizeConverter();
-
- @computed get createOperationParamsCache() { return this.HistoOp!.CreateOperationParameters(); }
- @computed get HistogramResult() { return this.HistoOp ? this.HistoOp.Result as HistogramResult : undefined; }
- @computed get BinRanges() { return this.HistogramResult ? this.HistogramResult.binRanges : undefined; }
- @computed get ChartType() {
- return !this.BinRanges ? ChartType.SinglePoint : this.BinRanges[0] instanceof AggregateBinRange ?
- (this.BinRanges[1] instanceof AggregateBinRange ? ChartType.SinglePoint : ChartType.HorizontalBar) :
- this.BinRanges[1] instanceof AggregateBinRange ? ChartType.VerticalBar : ChartType.HeatMap;
- }
-
- componentDidMount() {
- reaction(() => [CurrentUserUtils.ActiveSchemaName, this.props.doc.GetText(KeyStore.NorthstarSchema, "?")],
- (params: string[]) => params[0] === params[1] && this.activateHistogramOperation(), { fireImmediately: true });
- reaction(() => [this.VisualBinRanges && this.VisualBinRanges.slice()], () => this.SizeConverter.SetVisualBinRanges(this.VisualBinRanges));
- reaction(() => [this.PanelHeight, this.PanelWidth], () => this.SizeConverter.SetIsSmall(this.PanelWidth < 40 && this.PanelHeight < 40))
- reaction(() => this.HistogramResult ? this.HistogramResult.binRanges : undefined,
- (binRanges: BinRange[] | undefined) => {
- if (binRanges) {
- this.VisualBinRanges.splice(0, this.VisualBinRanges.length, ...binRanges.map((br, ind) =>
- VisualBinRangeHelper.GetVisualBinRange(br, this.HistogramResult!, ind ? this.HistoOp!.Y : this.HistoOp!.X, this.ChartType)));
-
- let valueAggregateKey = ModelHelpers.CreateAggregateKey(this.HistoOp!.V, this.HistogramResult!, ModelHelpers.AllBrushIndex(this.HistogramResult!));
- this.ValueRange = Object.values(this.HistogramResult!.bins!).reduce((prev, cur) => {
- let value = ModelHelpers.GetAggregateResult(cur, valueAggregateKey) as DoubleValueAggregateResult;
- return value && value.hasResult ? [Math.min(prev[0], value.result!), Math.max(prev[1], value.result!)] : prev;
- }, [Number.MIN_VALUE, Number.MAX_VALUE]);
- }
- });
- }
-
- activateHistogramOperation() {
- this.props.doc.GetTAsync(this.props.fieldKey, HistogramField).then((histoOp: Opt) => {
- if (histoOp) {
- runInAction(() => this.HistoOp = histoOp.Data);
- reaction(() => this.props.doc.GetList(KeyStore.LinkedFromDocs, []), docs => this.HistoOp!.Links.splice(0, this.HistoOp!.Links.length, ...docs), { fireImmediately: true });
- reaction(() => this.createOperationParamsCache, () => this.HistoOp!.Update(), { fireImmediately: true });
- }
- })
- }
- render() {
- let label = this.HistoOp && this.HistoOp.X ? this.HistoOp.X.AttributeModel.DisplayName : "<...>";
- var h = this.props.isTopMost ? this.PanelHeight : this.props.doc.GetNumber(KeyStore.Height, 0);
- var w = this.props.isTopMost ? this.PanelWidth : this.props.doc.GetNumber(KeyStore.Width, 0);
- let loff = this.SizeConverter.LeftOffset;
- let toff = this.SizeConverter.TopOffset;
- let roff = this.SizeConverter.RightOffset;
- let boff = this.SizeConverter.BottomOffset;
- return (
- runInAction(() => { this.PanelWidth = r.entry.width; this.PanelHeight = r.entry.height })}>
- {({ measureRef }) =>
-
- }
-
- )
- }
-}
-
diff --git a/src/client/views/nodes/HistogramBoxPrimitives.scss b/src/client/views/nodes/HistogramBoxPrimitives.scss
deleted file mode 100644
index 85f2c092d..000000000
--- a/src/client/views/nodes/HistogramBoxPrimitives.scss
+++ /dev/null
@@ -1,25 +0,0 @@
-.histogramboxprimitives-border {
- border: 3px;
- border-style: solid;
- border-color: #282828;
- pointer-events: none;
- position: absolute;
-}
-.histogramboxprimitives-bar {
- position: absolute;
- border: 1px;
- border-style: solid;
- border-color: #282828;
- pointer-events: all;
-}
-
-.histogramboxprimitives-placer {
- position: absolute;
- pointer-events: none;
- width: 100%;
- height: 100%;
-}
-.histogramboxprimitives-line {
- position: absolute;
- background: lightgray;
-}
\ No newline at end of file
diff --git a/src/client/views/nodes/HistogramBoxPrimitives.tsx b/src/client/views/nodes/HistogramBoxPrimitives.tsx
deleted file mode 100644
index f15cb5689..000000000
--- a/src/client/views/nodes/HistogramBoxPrimitives.tsx
+++ /dev/null
@@ -1,336 +0,0 @@
-import React = require("react")
-import { computed, observable, runInAction, trace } from "mobx";
-import { observer } from "mobx-react";
-import { Utils as DashUtils } from '../../../Utils';
-import { AttributeTransformationModel } from "../../northstar/core/attribute/AttributeTransformationModel";
-import { ChartType } from '../../northstar/model/binRanges/VisualBinRange';
-import { AggregateFunction, Bin, Brush, HistogramResult, MarginAggregateParameters, MarginAggregateResult, BinLabel } from "../../northstar/model/idea/idea";
-import { ModelHelpers } from "../../northstar/model/ModelHelpers";
-import { ArrayUtil } from "../../northstar/utils/ArrayUtil";
-import { LABColor } from '../../northstar/utils/LABcolor';
-import { PIXIRectangle } from "../../northstar/utils/MathUtil";
-import { StyleConstants } from "../../northstar/utils/StyleContants";
-import { HistogramBox, HistogramPrimitivesProps } from "./HistogramBox";
-import "./HistogramBoxPrimitives.scss";
-import { HistogramOperation } from "../../northstar/operations/HistogramOperation";
-import { FilterModel } from "../../northstar/core/filter/FilterModel";
-
-
-@observer
-export class HistogramBoxPrimitives extends React.Component {
- private get histoOp() { return this.props.HistoBox.HistoOp; }
- private get renderDimension() { return this.props.HistoBox.SizeConverter.RenderDimension; }
- @observable _selectedPrims: HistogramBinPrimitive[] = [];
- @computed get xaxislines() { return this.renderGridLinesAndLabels(0); }
- @computed get yaxislines() { return this.renderGridLinesAndLabels(1); }
- @computed get selectedPrimitives() { return this._selectedPrims.map(bp => this.drawRect(bp.Rect, bp.BarAxis, undefined, "border")); }
- @computed get binPrimitives() {
- let histoResult = this.props.HistoBox.HistogramResult;
- if (!histoResult || !histoResult.bins || !this.props.HistoBox.VisualBinRanges.length)
- return (null);
- let allBrushIndex = ModelHelpers.AllBrushIndex(histoResult);
- return Object.keys(histoResult.bins).reduce((prims, key) => {
- let drawPrims = new HistogramBinPrimitiveCollection(histoResult!.bins![key], this.props.HistoBox);
- let filterModel = ModelHelpers.GetBinFilterModel(histoResult!.bins![key], allBrushIndex, histoResult!, this.histoOp!.X, this.histoOp!.Y);
-
- this.props.HistoBox.HitTargets.setValue(drawPrims.HitGeom, filterModel);
-
- let toggle = this.getSelectionToggle(drawPrims.BinPrimitives, allBrushIndex, filterModel);
- drawPrims.BinPrimitives.filter(bp => bp.DataValue && bp.BrushIndex !== allBrushIndex).map(bp =>
- prims.push(...[{ r: bp.Rect, c: bp.Color }, { r: bp.MarginRect, c: StyleConstants.MARGIN_BARS_COLOR }].map(pair => this.drawRect(pair.r, bp.BarAxis, pair.c, "bar", toggle))));
- return prims;
- }, [] as JSX.Element[]);
- }
-
- private getSelectionToggle(binPrimitives: HistogramBinPrimitive[], allBrushIndex: number, filterModel: FilterModel) {
- let allBrushPrim = ArrayUtil.FirstOrDefault(binPrimitives, bp => bp.BrushIndex == allBrushIndex);
- return !allBrushPrim ? () => { } : () => runInAction(() => {
- if (ArrayUtil.Contains(this.histoOp!.FilterModels, filterModel)) {
- this._selectedPrims.splice(this._selectedPrims.indexOf(allBrushPrim!), 1);
- this.histoOp!.RemoveFilterModels([filterModel]);
- }
- else {
- this._selectedPrims.push(allBrushPrim!);
- this.histoOp!.AddFilterModels([filterModel]);
- }
- })
- }
-
- private renderGridLinesAndLabels(axis: number) {
- if (!this.props.HistoBox.SizeConverter.Initialized)
- return (null);
- let labels = this.props.HistoBox.VisualBinRanges[axis].GetLabels();
- return labels.reduce((prims, binLabel, i) => {
- let r = this.props.HistoBox.SizeConverter.DataToScreenRange(binLabel.minValue!, binLabel.maxValue!, axis);
- prims.push(this.drawLine(r.xFrom, r.yFrom, axis == 0 ? 0 : r.xTo - r.xFrom, axis == 0 ? r.yTo - r.yFrom : 0));
- if (i == labels.length - 1)
- prims.push(this.drawLine(axis == 0 ? r.xTo : r.xFrom, axis == 0 ? r.yFrom : r.yTo, axis == 0 ? 0 : r.xTo - r.xFrom, axis == 0 ? r.yTo - r.yFrom : 0));
- return prims;
- }, [] as JSX.Element[]);
- }
-
- drawEntity(xFrom: number, yFrom: number, entity: JSX.Element) {
- let transXpercent = xFrom / this.renderDimension * 100;
- let transYpercent = yFrom / this.renderDimension * 100;
- return (
- {entity}
-
);
- }
- drawLine(xFrom: number, yFrom: number, width: number, height: number) {
- if (height < 0) {
- yFrom += height;
- height = -height;
- }
- if (width < 0) {
- xFrom += width;
- width = -width;
- }
- let trans2Xpercent = width == 0 ? `1px` : `${(xFrom + width) / this.renderDimension * 100}%`;
- let trans2Ypercent = height == 0 ? `1px` : `${(yFrom + height) / this.renderDimension * 100}%`;
- let line = ();
- return this.drawEntity(xFrom, yFrom, line);
- }
-
- drawRect(r: PIXIRectangle, barAxis: number, color: number | undefined, classExt: string, tapHandler: () => void = () => { }) {
- let widthPercent = r.width / this.renderDimension * 100;
- let heightPercent = r.height / this.renderDimension * 100;
- let rect = ( { if (e.button == 0) tapHandler() }}
- style={{
- borderBottomStyle: barAxis == 1 ? "none" : "solid",
- borderLeftStyle: barAxis == 0 ? "none" : "solid",
- width: `${widthPercent}%`,
- height: `${heightPercent}%`,
- background: color ? `${LABColor.RGBtoHexString(color)}` : ""
- }}
- />);
- return this.drawEntity(r.x, r.y, rect);
- }
- render() {
- return
- {this.xaxislines}
- {this.yaxislines}
- {this.binPrimitives}
- {this.selectedPrimitives}
-
- }
-}
-
-class HistogramBinPrimitive {
- constructor(init?: Partial
) {
- Object.assign(this, init);
- }
- public DataValue: number = 0;
- public Rect: PIXIRectangle = PIXIRectangle.EMPTY;
- public MarginRect: PIXIRectangle = PIXIRectangle.EMPTY;
- public MarginPercentage: number = 0;
- public Color: number = StyleConstants.WARNING_COLOR;
- public Opacity: number = 1;
- public BrushIndex: number = 0;
- public BarAxis: number = -1;
-}
-
-export class HistogramBinPrimitiveCollection {
- private static TOLERANCE: number = 0.0001;
-
- private _histoBox: HistogramBox;
- private get histoOp() { return this._histoBox.HistoOp!; }
- private get histoResult() { return this.histoOp.Result as HistogramResult; }
- private get sizeConverter() { return this._histoBox.SizeConverter!; }
- public BinPrimitives: Array = new Array();
- public HitGeom: PIXIRectangle = PIXIRectangle.EMPTY;
-
- constructor(bin: Bin, histoBox: HistogramBox) {
- this._histoBox = histoBox;
- let brushing = this.setupBrushing(bin, this.histoOp.Normalization); // X= 0, Y = 1, V = 2
-
- brushing.orderedBrushes.reduce((brushFactorSum, brush) => {
- switch (histoBox.ChartType) {
- case ChartType.VerticalBar: return this.createVerticalBarChartBinPrimitives(bin, brush, brushing.maxAxis, this.histoOp.Normalization);
- case ChartType.HorizontalBar: return this.createHorizontalBarChartBinPrimitives(bin, brush, brushing.maxAxis, this.histoOp.Normalization);
- case ChartType.SinglePoint: return this.createSinglePointChartBinPrimitives(bin, brush);
- case ChartType.HeatMap: return this.createHeatmapBinPrimitives(bin, brush, brushFactorSum);
- }
- }, 0);
-
- // adjust brush rects (stacking or not)
- var allBrushIndex = ModelHelpers.AllBrushIndex(this.histoResult);
- var filteredBinPrims = this.BinPrimitives.filter(b => b.BrushIndex != allBrushIndex && b.DataValue != 0.0);
- filteredBinPrims.reduce((sum, fbp) => {
- if (histoBox.ChartType == ChartType.VerticalBar) {
- if (this.histoOp.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);
- return sum + fbp.Rect.height;
- }
- if (this.histoOp.Y.AggregateFunction == AggregateFunction.Avg) {
- var w = fbp.Rect.width / 2.0;
- fbp.Rect = new PIXIRectangle(fbp.Rect.x + sum, fbp.Rect.y, fbp.Rect.width / filteredBinPrims.length, fbp.Rect.height);
- fbp.MarginRect = new PIXIRectangle(fbp.MarginRect.x - w + sum + (fbp.Rect.width / 2.0), fbp.MarginRect.y, fbp.MarginRect.width, fbp.MarginRect.height);
- return sum + fbp.Rect.width;
- }
- }
- else if (histoBox.ChartType == ChartType.HorizontalBar) {
- if (this.histoOp.X.AggregateFunction == AggregateFunction.Count) {
- fbp.Rect = new PIXIRectangle(fbp.Rect.x + sum, fbp.Rect.y, fbp.Rect.width, fbp.Rect.height);
- fbp.MarginRect = new PIXIRectangle(fbp.MarginRect.x + sum, fbp.MarginRect.y, fbp.MarginRect.width, fbp.MarginRect.height);
- return sum + fbp.Rect.width;
- }
- if (this.histoOp.X.AggregateFunction == AggregateFunction.Avg) {
- var h = fbp.Rect.height / 2.0;
- fbp.Rect = new PIXIRectangle(fbp.Rect.x, fbp.Rect.y + sum, fbp.Rect.width, fbp.Rect.height / filteredBinPrims.length);
- fbp.MarginRect = new PIXIRectangle(fbp.MarginRect.x, fbp.MarginRect.y - h + sum + (fbp.Rect.height / 2.0), fbp.MarginRect.width, fbp.MarginRect.height);
- return sum + fbp.Rect.height;
- }
- }
- return 0;
- }, 0);
- this.BinPrimitives = this.BinPrimitives.reverse();
- var f = this.BinPrimitives.filter(b => b.BrushIndex == allBrushIndex);
- this.HitGeom = f.length > 0 ? f[0].Rect : PIXIRectangle.EMPTY;
- }
- private setupBrushing(bin: Bin, normalization: number) {
- var overlapBrushIndex = ModelHelpers.OverlapBrushIndex(this.histoResult);
- var orderedBrushes = [this.histoResult.brushes![0], this.histoResult.brushes![overlapBrushIndex]];
- this.histoResult.brushes!.map(brush => brush.brushIndex != 0 && brush.brushIndex != overlapBrushIndex && orderedBrushes.push(brush));
- return {
- orderedBrushes,
- maxAxis: orderedBrushes.reduce((prev, Brush) => {
- let aggResult = this.histoOp.getValue(normalization, bin, this.histoResult, Brush.brushIndex!);
- return aggResult != undefined && aggResult > prev ? aggResult : prev;
- }, Number.MIN_VALUE)
- };
- }
- private createHeatmapBinPrimitives(bin: Bin, brush: Brush, brushFactorSum: number): number {
-
- let unNormalizedValue = this.histoOp!.getValue(2, bin, this.histoResult, brush.brushIndex!);
- if (unNormalizedValue == undefined)
- return brushFactorSum;
-
- var normalizedValue = (unNormalizedValue - this._histoBox.ValueRange[0]) / (Math.abs((this._histoBox.ValueRange[1] - this._histoBox.ValueRange[0])) < HistogramBinPrimitiveCollection.TOLERANCE ?
- unNormalizedValue : this._histoBox.ValueRange[1] - this._histoBox.ValueRange[0]);
-
- let allUnNormalizedValue = this.histoOp.getValue(2, bin, this.histoResult, ModelHelpers.AllBrushIndex(this.histoResult))
-
- // bcz: are these calls needed?
- let [xFrom, xTo] = this.sizeConverter.DataToScreenAxisRange(this._histoBox.VisualBinRanges, 0, bin);
- let [yFrom, yTo] = this.sizeConverter.DataToScreenAxisRange(this._histoBox.VisualBinRanges, 1, bin);
-
- var returnBrushFactorSum = brushFactorSum;
- if (allUnNormalizedValue != undefined) {
- var brushFactor = (unNormalizedValue / allUnNormalizedValue);
- returnBrushFactorSum += brushFactor;
- returnBrushFactorSum = Math.min(returnBrushFactorSum, 1.0);
-
- var tempRect = new PIXIRectangle(xFrom, yTo, xTo - xFrom, yFrom - yTo);
- var ratio = (tempRect.width / tempRect.height);
- var newHeight = Math.sqrt((1.0 / ratio) * ((tempRect.width * tempRect.height) * returnBrushFactorSum));
- var newWidth = newHeight * ratio;
-
- xFrom = (tempRect.x + (tempRect.width - newWidth) / 2.0);
- yTo = (tempRect.y + (tempRect.height - newHeight) / 2.0);
- xTo = (xFrom + newWidth);
- yFrom = (yTo + newHeight);
- }
- var alpha = 0.0;
- var color = this.baseColorFromBrush(brush);
- var lerpColor = LABColor.Lerp(
- LABColor.FromColor(StyleConstants.MIN_VALUE_COLOR),
- LABColor.FromColor(color),
- (alpha + Math.pow(normalizedValue, 1.0 / 3.0) * (1.0 - alpha)));
- var dataColor = LABColor.ToColor(lerpColor);
-
- this.createBinPrimitive(-1, brush, PIXIRectangle.EMPTY, 0, xFrom, xTo, yFrom, yTo, dataColor, 1, unNormalizedValue);
- return returnBrushFactorSum;
- }
-
- private createSinglePointChartBinPrimitives(bin: Bin, brush: Brush): number {
- let unNormalizedValue = this._histoBox.HistoOp!.getValue(2, bin, this.histoResult, brush.brushIndex!);
- if (unNormalizedValue != undefined) {
- let [xFrom, xTo] = this.sizeConverter.DataToScreenPointRange(0, bin, ModelHelpers.CreateAggregateKey(this.histoOp.X, this.histoResult, brush.brushIndex!));
- let [yFrom, yTo] = this.sizeConverter.DataToScreenPointRange(1, bin, ModelHelpers.CreateAggregateKey(this.histoOp.Y, this.histoResult, brush.brushIndex!));
-
- if (xFrom != undefined && yFrom != undefined && xTo != undefined && yTo != undefined)
- this.createBinPrimitive(-1, brush, PIXIRectangle.EMPTY, 0, xFrom, xTo, yFrom, yTo, this.baseColorFromBrush(brush), 1, unNormalizedValue);
- }
- return 0;
- }
-
- private createVerticalBarChartBinPrimitives(bin: Bin, brush: Brush, binBrushMaxAxis: number, normalization: number): number {
- let dataValue = this.histoOp.getValue(1, bin, this.histoResult, brush.brushIndex!);
- if (dataValue != undefined) {
- let [yFrom, yValue, yTo] = this.sizeConverter.DataToScreenNormalizedRange(dataValue, normalization, 1, binBrushMaxAxis);
- let [xFrom, xTo] = this.sizeConverter.DataToScreenAxisRange(this._histoBox.VisualBinRanges, 0, bin);
-
- var yMarginAbsolute = this.getMargin(bin, brush, this.histoOp.Y);
- var marginRect = new PIXIRectangle(xFrom + (xTo - xFrom) / 2.0 - 1,
- this.sizeConverter.DataToScreenY(yValue + yMarginAbsolute), 2,
- this.sizeConverter.DataToScreenY(yValue - yMarginAbsolute) - this.sizeConverter.DataToScreenY(yValue + yMarginAbsolute));
-
- this.createBinPrimitive(1, brush, marginRect, 0, xFrom, xTo, yFrom, yTo,
- this.baseColorFromBrush(brush), normalization != 0 ? 1 : 0.6 * binBrushMaxAxis / this.sizeConverter.DataRanges[1] + 0.4, dataValue);
- }
- return 0;
- }
-
- private createHorizontalBarChartBinPrimitives(bin: Bin, brush: Brush, binBrushMaxAxis: number, normalization: number): number {
- let dataValue = this.histoOp.getValue(0, bin, this.histoResult, brush.brushIndex!);
- if (dataValue != undefined) {
- let [xFrom, xValue, xTo] = this.sizeConverter.DataToScreenNormalizedRange(dataValue, normalization, 0, binBrushMaxAxis);
- let [yFrom, yTo] = this.sizeConverter.DataToScreenAxisRange(this._histoBox.VisualBinRanges, 1, bin);
-
- var xMarginAbsolute = this.sizeConverter.IsSmall ? 0 : this.getMargin(bin, brush, this.histoOp.X);
- var marginRect = new PIXIRectangle(this.sizeConverter.DataToScreenX(xValue - xMarginAbsolute),
- yTo + (yFrom - yTo) / 2.0 - 1,
- this.sizeConverter.DataToScreenX(xValue + xMarginAbsolute) - this.sizeConverter.DataToScreenX(xValue - xMarginAbsolute),
- 2.0);
-
- this.createBinPrimitive(0, brush, marginRect, 0, xFrom, xTo, yFrom, yTo,
- this.baseColorFromBrush(brush), normalization != 1 ? 1 : 0.6 * binBrushMaxAxis / this.sizeConverter.DataRanges[0] + 0.4, dataValue);
- }
- return 0;
- }
-
-
- private getMargin(bin: Bin, brush: Brush, axis: AttributeTransformationModel) {
- var marginParams = new MarginAggregateParameters();
- marginParams.aggregateFunction = axis.AggregateFunction;
- var marginAggregateKey = ModelHelpers.CreateAggregateKey(axis, this.histoResult, brush.brushIndex!, marginParams);
- var marginResult = ModelHelpers.GetAggregateResult(bin, marginAggregateKey) as MarginAggregateResult;
- return !marginResult ? 0 : marginResult.absolutMargin!;
- }
-
- private createBinPrimitive(barAxis: number, brush: Brush, marginRect: PIXIRectangle,
- marginPercentage: number, xFrom: number, xTo: number, yFrom: number, yTo: number, color: number, opacity: number, dataValue: number) {
- var binPrimitive = new HistogramBinPrimitive(
- {
- Rect: new PIXIRectangle(xFrom, yTo, xTo - xFrom, yFrom - yTo),
- MarginRect: marginRect,
- MarginPercentage: marginPercentage,
- BrushIndex: brush.brushIndex,
- Color: color,
- Opacity: opacity,
- DataValue: dataValue,
- BarAxis: barAxis
- });
- this.BinPrimitives.push(binPrimitive);
- }
-
- private baseColorFromBrush(brush: Brush): number {
- if (brush.brushIndex == ModelHelpers.RestBrushIndex(this.histoResult)) {
- return StyleConstants.HIGHLIGHT_COLOR;
- }
- else if (brush.brushIndex == ModelHelpers.OverlapBrushIndex(this.histoResult)) {
- return StyleConstants.OVERLAP_COLOR;
- }
- else if (brush.brushIndex == ModelHelpers.AllBrushIndex(this.histoResult)) {
- return 0x00ff00;
- }
- else if (this.histoOp.BrushColors.length > 0) {
- return this.histoOp.BrushColors[brush.brushIndex! % this.histoOp.BrushColors.length];
- }
- return StyleConstants.HIGHLIGHT_COLOR;
- }
-}
\ No newline at end of file
diff --git a/src/client/views/nodes/HistogramLabelPrimitives.scss b/src/client/views/nodes/HistogramLabelPrimitives.scss
deleted file mode 100644
index d8ee88d72..000000000
--- a/src/client/views/nodes/HistogramLabelPrimitives.scss
+++ /dev/null
@@ -1,12 +0,0 @@
-
- .histogramLabelPrimitives-gridlabel {
- position:absolute;
- transform-origin: left top;
- font-size: 11;
- }
- .histogramLabelPrimitives-placer {
- position:absolute;
- width:100%;
- height:100%;
- pointer-events: none;
- }
\ No newline at end of file
diff --git a/src/client/views/nodes/HistogramLabelPrimitives.tsx b/src/client/views/nodes/HistogramLabelPrimitives.tsx
deleted file mode 100644
index 7f365e45b..000000000
--- a/src/client/views/nodes/HistogramLabelPrimitives.tsx
+++ /dev/null
@@ -1,78 +0,0 @@
-import React = require("react")
-import { action, computed, reaction } from "mobx";
-import { observer } from "mobx-react";
-import { Utils as DashUtils } from '../../../Utils';
-import { NominalVisualBinRange } from "../../northstar/model/binRanges/NominalVisualBinRange";
-import { StyleConstants } from "../../northstar/utils/StyleContants";
-import "./../../northstar/utils/Extensions";
-import "./HistogramLabelPrimitives.scss";
-import { HistogramBox, HistogramPrimitivesProps } from "./HistogramBox";
-
-@observer
-export class HistogramLabelPrimitives extends React.Component {
- componentDidMount() {
- reaction(() => [this.props.HistoBox.PanelWidth, this.props.HistoBox.SizeConverter.LeftOffset, this.props.HistoBox.VisualBinRanges.length],
- (fields) => HistogramLabelPrimitives.computeLabelAngle(fields[0] as number, fields[1] as number, this.props.HistoBox), { fireImmediately: true });
- }
-
- @action
- static computeLabelAngle(panelWidth: number, leftOffset: number, histoBox: HistogramBox) {
- const textWidth = 30;
- if (panelWidth > 0 && histoBox.VisualBinRanges.length && histoBox.VisualBinRanges[0] instanceof NominalVisualBinRange) {
- let space = (panelWidth - leftOffset * 2) / histoBox.VisualBinRanges[0].GetBins().length;
- histoBox.SizeConverter.SetLabelAngle(Math.min(Math.PI / 2, Math.max(Math.PI / 6, textWidth / space * Math.PI / 2)));
- } else if (histoBox.SizeConverter.LabelAngle) {
- histoBox.SizeConverter.SetLabelAngle(0);
- }
- }
- @computed get xaxislines() { return this.renderGridLinesAndLabels(0); }
- @computed get yaxislines() { return this.renderGridLinesAndLabels(1); }
-
- private renderGridLinesAndLabels(axis: number) {
- let sc = this.props.HistoBox.SizeConverter;
- let vb = this.props.HistoBox.VisualBinRanges;
- if (!vb.length || !sc.Initialized)
- return (null);
- let dim = (axis == 0 ? this.props.HistoBox.PanelWidth : this.props.HistoBox.PanelHeight) / ((axis == 0 && vb[axis] instanceof NominalVisualBinRange) ?
- (12 + 5) : // (FontStyles.AxisLabel.fontSize + 5)));
- sc.MaxLabelSizes[axis].coords[axis] + 5);
-
- let labels = vb[axis].GetLabels();
- return labels.reduce((prims, binLabel, i) => {
- let r = sc.DataToScreenRange(binLabel.minValue!, binLabel.maxValue!, axis);
- if (i % Math.ceil(labels.length / dim) === 0 && binLabel.label) {
- const label = binLabel.label.Truncate(StyleConstants.MAX_CHAR_FOR_HISTOGRAM_LABELS, "...");
- const textHeight = 14; const textWidth = 30;
- let xStart = (axis === 0 ? r.xFrom + (r.xTo - r.xFrom) / 2.0 : r.xFrom - 10 - textWidth);
- let yStart = (axis === 1 ? r.yFrom - textHeight / 2 : r.yFrom);
-
- if (axis == 0 && vb[axis] instanceof NominalVisualBinRange) {
- let space = (r.xTo - r.xFrom) / sc.RenderDimension * this.props.HistoBox.PanelWidth;
- xStart += Math.max(textWidth / 2, (1 - textWidth / space) * textWidth / 2) - textHeight / 2;
- }
-
- let xPercent = axis == 1 ? `${xStart}px` : `${xStart / sc.RenderDimension * 100}%`
- let yPercent = axis == 0 ? `${this.props.HistoBox.PanelHeight - sc.BottomOffset - textHeight}px` : `${yStart / sc.RenderDimension * 100}%`
-
- prims.push(
-
- )
- }
- return prims;
- }, [] as JSX.Element[]);
- }
-
- render() {
- let xaxislines = this.xaxislines;
- let yaxislines = this.yaxislines;
- return
- {xaxislines}
- {yaxislines}
-
- }
-
-}
\ No newline at end of file
diff --git a/src/fields/HistogramField.ts b/src/fields/HistogramField.ts
deleted file mode 100644
index bb0014ab3..000000000
--- a/src/fields/HistogramField.ts
+++ /dev/null
@@ -1,59 +0,0 @@
-import { BasicField } from "./BasicField";
-import { Field, FieldId } from "./Field";
-import { Types } from "../server/Message";
-import { HistogramOperation } from "../client/northstar/operations/HistogramOperation";
-import { action } from "mobx";
-import { AttributeTransformationModel } from "../client/northstar/core/attribute/AttributeTransformationModel";
-import { ColumnAttributeModel } from "../client/northstar/core/attribute/AttributeModel";
-import { CurrentUserUtils } from "../server/authentication/models/current_user_utils";
-
-
-export class HistogramField extends BasicField {
- constructor(data?: HistogramOperation, id?: FieldId, save: boolean = true) {
- super(data ? data : HistogramOperation.Empty, save, id);
- }
-
- toString(): string {
- return JSON.stringify(this.Data);
- }
-
- Copy(): Field {
- return new HistogramField(this.Data);
- }
-
- ToScriptString(): string {
- return `new HistogramField("${this.Data}")`;
- }
-
- ToJson(): { type: Types, data: string, _id: string } {
- return {
- type: Types.HistogramOp,
- data: JSON.stringify(this.Data),
- _id: this.Id
- }
- }
-
- @action
- static FromJson(id: string, data: any): HistogramField {
- let jp = JSON.parse(data);
- let X: AttributeTransformationModel | undefined;
- let Y: AttributeTransformationModel | undefined;
- let V: AttributeTransformationModel | undefined;
-
- CurrentUserUtils.GetAllNorthstarColumnAttributes().map(attr => {
- if (attr.displayName == jp.X.AttributeModel.Attribute.DisplayName) {
- X = new AttributeTransformationModel(new ColumnAttributeModel(attr), jp.X.AggregateFunction);
- }
- if (attr.displayName == jp.Y.AttributeModel.Attribute.DisplayName) {
- Y = new AttributeTransformationModel(new ColumnAttributeModel(attr), jp.Y.AggregateFunction);
- }
- if (attr.displayName == jp.V.AttributeModel.Attribute.DisplayName) {
- V = new AttributeTransformationModel(new ColumnAttributeModel(attr), jp.V.AggregateFunction);
- }
- });
- if (X && Y && V) {
- return new HistogramField(new HistogramOperation(X, Y, V, jp.Normalization), id, false);
- }
- return new HistogramField(HistogramOperation.Empty, id, false);
- }
-}
\ No newline at end of file
diff --git a/src/fields/KeyStore.ts b/src/fields/KeyStore.ts
index 09dddf962..aa0b9ce92 100644
--- a/src/fields/KeyStore.ts
+++ b/src/fields/KeyStore.ts
@@ -44,5 +44,4 @@ export namespace KeyStore {
export const Archives = new Key("Archives");
export const Updated = new Key("Updated");
export const Workspaces = new Key("Workspaces");
- export const NorthstarSchema = new Key("NorthstarSchema");
}
diff --git a/src/server/ServerUtil.ts b/src/server/ServerUtil.ts
index f958df04b..98a7a1451 100644
--- a/src/server/ServerUtil.ts
+++ b/src/server/ServerUtil.ts
@@ -17,8 +17,7 @@ import { VideoField } from '../fields/VideoField';
import { InkField } from '../fields/InkField';
import { PDFField } from '../fields/PDFField';
import { TupleField } from '../fields/TupleField';
-import { HistogramField } from '../fields/HistogramField';
-
+import { HistogramField } from '../client/northstar/dash-fields/HistogramField';
diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts
index 4b42e40b6..0ac85b446 100644
--- a/src/server/authentication/models/current_user_utils.ts
+++ b/src/server/authentication/models/current_user_utils.ts
@@ -7,8 +7,9 @@ import { Document } from "../../../fields/Document";
import { KeyStore } from "../../../fields/KeyStore";
import { ListField } from "../../../fields/ListField";
import { Documents } from "../../../client/documents/Documents";
-import { Schema, Attribute, AttributeGroup } from "../../../client/northstar/model/idea/idea";
+import { Schema, Attribute, AttributeGroup, Catalog } from "../../../client/northstar/model/idea/idea";
import { observable, computed, action } from "mobx";
+import { ArrayUtil } from "../../../client/northstar/utils/ArrayUtil";
export class CurrentUserUtils {
private static curr_email: string;
@@ -16,8 +17,7 @@ export class CurrentUserUtils {
private static user_document: Document;
//TODO tfs: these should be temporary...
private static mainDocId: string | undefined;
- private static activeSchema: Schema | undefined;
- @observable public static ActiveSchemaName: string = "";
+ @observable private static catalog?: Catalog;
public static get email(): string {
return this.curr_email;
@@ -39,12 +39,18 @@ export class CurrentUserUtils {
this.mainDocId = id;
}
-
- public static get ActiveSchema(): Schema | undefined {
- return this.activeSchema;
+ @computed public static get NorthstarDBCatalog(): Catalog | undefined {
+ return this.catalog;
+ }
+ public static set NorthstarDBCatalog(ctlog: Catalog | undefined) {
+ this.catalog = ctlog;
}
- public static GetAllNorthstarColumnAttributes() {
- if (!this.ActiveSchema || !this.ActiveSchema.rootAttributeGroup) {
+ public static GetNorthstarSchema(name: string): Schema | undefined {
+ return !this.catalog || !this.catalog.schemas ? undefined :
+ ArrayUtil.FirstOrDefault(this.catalog.schemas, (s: Schema) => s.displayName === name);
+ }
+ public static GetAllNorthstarColumnAttributes(schema: Schema) {
+ if (!schema || !schema.rootAttributeGroup) {
return [];
}
const recurs = (attrs: Attribute[], g: AttributeGroup) => {
@@ -56,13 +62,10 @@ export class CurrentUserUtils {
}
};
const allAttributes: Attribute[] = new Array();
- recurs(allAttributes, this.ActiveSchema.rootAttributeGroup);
+ recurs(allAttributes, schema.rootAttributeGroup);
return allAttributes;
}
- public static set ActiveSchema(id: Schema | undefined) {
- this.activeSchema = id;
- }
private static createUserDocument(id: string): Document {
let doc = new Document(id);
--
cgit v1.2.3-70-g09d2
From a10bbd686a825ee38caceb7ecfc388715c14a817 Mon Sep 17 00:00:00 2001
From: bob
Date: Fri, 29 Mar 2019 16:18:55 -0400
Subject: added basic brushing placeholder
---
.../northstar/core/brusher/BrushLinkModel.ts | 40 ------------------
.../northstar/core/brusher/IBaseBrushable.ts | 4 +-
src/client/northstar/dash-nodes/HistogramBox.tsx | 19 +++++----
.../dash-nodes/HistogramBoxPrimitives.tsx | 5 ++-
.../northstar/operations/HistogramOperation.ts | 48 +++++++++++-----------
5 files changed, 43 insertions(+), 73 deletions(-)
delete mode 100644 src/client/northstar/core/brusher/BrushLinkModel.ts
(limited to 'src/client/northstar/operations')
diff --git a/src/client/northstar/core/brusher/BrushLinkModel.ts b/src/client/northstar/core/brusher/BrushLinkModel.ts
deleted file mode 100644
index e3ac43367..000000000
--- a/src/client/northstar/core/brusher/BrushLinkModel.ts
+++ /dev/null
@@ -1,40 +0,0 @@
-import { IBaseBrushable } from '../brusher/IBaseBrushable'
-import { IBaseBrusher } from '../brusher/IBaseBrusher'
-import { Utils } from '../../utils/Utils'
-import { IEquatable } from '../../utils/IEquatable';
-
-export class BrushLinkModel implements IEquatable {
-
- public From: IBaseBrusher;
-
- public To: IBaseBrushable;
-
- public Color: number = 0;
-
- constructor(from: IBaseBrusher, to: IBaseBrushable) {
- this.From = from;
- this.To = to;
- }
-
- public static overlaps(start: number, end: number, otherstart: number, otherend: number): boolean {
- if (start > otherend || otherstart > end)
- return false;
- return true;
- }
- public static Connected(from: IBaseBrusher, to: IBaseBrushable): boolean {
- var connected = (Math.abs(from.Position.x + from.Size.x - to.Position.x) <= 60 &&
- this.overlaps(from.Position.y, from.Position.y + from.Size.y, to.Position.y, to.Position.y + to.Size.y)
- ) ||
- (Math.abs(to.Position.x + to.Size.x - from.Position.x) <= 60 &&
- this.overlaps(to.Position.y, to.Position.y + to.Size.y, from.Position.y, from.Position.y + from.Size.y)
- );
- return connected;
- }
-
- public Equals(other: Object): boolean {
- if (!Utils.EqualityHelper(this, other)) return false;
- if (!this.From.Equals((other as BrushLinkModel).From)) return false;
- if (!this.To.Equals((other as BrushLinkModel).To)) return false;
- return true;
- }
-}
\ No newline at end of file
diff --git a/src/client/northstar/core/brusher/IBaseBrushable.ts b/src/client/northstar/core/brusher/IBaseBrushable.ts
index 07d4e7580..99a36636f 100644
--- a/src/client/northstar/core/brusher/IBaseBrushable.ts
+++ b/src/client/northstar/core/brusher/IBaseBrushable.ts
@@ -1,9 +1,9 @@
-import { BrushLinkModel } from '../brusher/BrushLinkModel'
import { PIXIPoint } from '../../utils/MathUtil'
import { IEquatable } from '../../utils/IEquatable';
+import { Document } from '../../../../fields/Document'
export interface IBaseBrushable extends IEquatable {
- BrusherModels: Array>;
+ BrusherModels: Array;
BrushColors: Array;
Position: PIXIPoint;
Size: PIXIPoint;
diff --git a/src/client/northstar/dash-nodes/HistogramBox.tsx b/src/client/northstar/dash-nodes/HistogramBox.tsx
index dba4ce900..b464e125c 100644
--- a/src/client/northstar/dash-nodes/HistogramBox.tsx
+++ b/src/client/northstar/dash-nodes/HistogramBox.tsx
@@ -2,26 +2,25 @@ import React = require("react")
import { action, computed, observable, reaction, runInAction } from "mobx";
import { observer } from "mobx-react";
import Measure from "react-measure";
-import { Dictionary } from "typescript-collections";
import { FieldWaiting, Opt } from "../../../fields/Field";
+import { Document } from "../../../fields/Document";
import { KeyStore } from "../../../fields/KeyStore";
import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils";
-import { FilterModel } from '../../northstar/core/filter/FilterModel';
import { ChartType, VisualBinRange } from '../../northstar/model/binRanges/VisualBinRange';
import { VisualBinRangeHelper } from "../../northstar/model/binRanges/VisualBinRangeHelper";
-import { AggregateBinRange, BinRange, DoubleValueAggregateResult, HistogramResult, Catalog, AggregateFunction } from "../../northstar/model/idea/idea";
+import { AggregateBinRange, AggregateFunction, BinRange, Catalog, DoubleValueAggregateResult, HistogramResult } from "../../northstar/model/idea/idea";
import { ModelHelpers } from "../../northstar/model/ModelHelpers";
import { HistogramOperation } from "../../northstar/operations/HistogramOperation";
-import { PIXIRectangle } from "../../northstar/utils/MathUtil";
import { SizeConverter } from "../../northstar/utils/SizeConverter";
import { DragManager } from "../../util/DragManager";
import { FieldView, FieldViewProps } from "../../views/nodes/FieldView";
+import { AttributeTransformationModel } from "../core/attribute/AttributeTransformationModel";
import { HistogramField } from "../dash-fields/HistogramField";
-import "../utils/Extensions"
+import "../utils/Extensions";
import "./HistogramBox.scss";
import { HistogramBoxPrimitives } from './HistogramBoxPrimitives';
import { HistogramLabelPrimitives } from "./HistogramLabelPrimitives";
-import { AttributeTransformationModel } from "../core/attribute/AttributeTransformationModel";
+import { StyleConstants } from "../utils/StyleContants";
export interface HistogramPrimitivesProps {
HistoBox: HistogramBox;
@@ -124,7 +123,13 @@ export class HistogramBox extends React.Component {
this.props.doc.GetTAsync(this.props.fieldKey, HistogramField).then((histoOp: Opt) => runInAction(() => {
this.HistoOp = histoOp ? histoOp.Data : HistogramOperation.Empty;
if (this.HistoOp != HistogramOperation.Empty) {
- reaction(() => this.props.doc.GetList(KeyStore.LinkedFromDocs, []), docs => this.HistoOp.Links.splice(0, this.HistoOp.Links.length, ...docs), { fireImmediately: true });
+ reaction(() => this.props.doc.GetList(KeyStore.LinkedFromDocs, []),
+ (docs: Document[]) => {
+ var availableColors = StyleConstants.BRUSH_COLORS.map(c => c);
+ docs.map((brush, i) => brush.SetNumber(KeyStore.BackgroundColor, availableColors[i % availableColors.length]));
+ this.HistoOp.BrushLinks.splice(0, this.HistoOp.BrushLinks.length, ...docs);
+ //this.HistoOp.Links.splice(0, this.HistoOp.Links.length, ...docs)
+ }, { fireImmediately: true });
reaction(() => this.createOperationParamsCache, () => this.HistoOp.Update(), { fireImmediately: true });
}
}));
diff --git a/src/client/northstar/dash-nodes/HistogramBoxPrimitives.tsx b/src/client/northstar/dash-nodes/HistogramBoxPrimitives.tsx
index 5e403eb9c..b8020c28c 100644
--- a/src/client/northstar/dash-nodes/HistogramBoxPrimitives.tsx
+++ b/src/client/northstar/dash-nodes/HistogramBoxPrimitives.tsx
@@ -168,7 +168,7 @@ export class HistogramBinPrimitiveCollection {
var filteredBinPrims = this.BinPrimitives.filter(b => b.BrushIndex != allBrushIndex && b.DataValue != 0.0);
filteredBinPrims.reduce((sum, fbp) => {
if (histoBox.ChartType == ChartType.VerticalBar) {
- if (this.histoOp.X.AggregateFunction == AggregateFunction.Count) {
+ if (this.histoOp.Y.AggregateFunction == AggregateFunction.Count) {
fbp.Rect = new PIXIRectangle(fbp.Rect.x, fbp.Rect.y - sum, fbp.Rect.width, fbp.Rect.height);
fbp.MarginRect = new PIXIRectangle(fbp.MarginRect.x, fbp.MarginRect.y - sum, fbp.MarginRect.width, fbp.MarginRect.height);
return sum + fbp.Rect.height;
@@ -269,6 +269,9 @@ export class HistogramBinPrimitiveCollection {
private createVerticalBarChartBinPrimitives(bin: Bin, brush: Brush, binBrushMaxAxis: number, normalization: number): number {
let dataValue = this.histoOp.getValue(1, bin, this.histoResult, brush.brushIndex!);
if (dataValue != undefined) {
+ if (bin.binIndex!.indices![0] == 0 && bin.binIndex!.indices![1] == 0) {
+ console.log("DV = " + dataValue)
+ }
let [yFrom, yValue, yTo] = this.sizeConverter.DataToScreenNormalizedRange(dataValue, normalization, 1, binBrushMaxAxis);
let [xFrom, xTo] = this.sizeConverter.DataToScreenXAxisRange(this._histoBox.VisualBinRanges, 0, bin);
diff --git a/src/client/northstar/operations/HistogramOperation.ts b/src/client/northstar/operations/HistogramOperation.ts
index 8a0f648f6..fa51e2a8c 100644
--- a/src/client/northstar/operations/HistogramOperation.ts
+++ b/src/client/northstar/operations/HistogramOperation.ts
@@ -4,29 +4,30 @@ import { CurrentUserUtils } from "../../../server/authentication/models/current_
import { ColumnAttributeModel } from "../core/attribute/AttributeModel";
import { AttributeTransformationModel } from "../core/attribute/AttributeTransformationModel";
import { CalculatedAttributeManager } from "../core/attribute/CalculatedAttributeModel";
-import { BrushLinkModel } from "../core/brusher/BrushLinkModel";
import { FilterModel } from "../core/filter/FilterModel";
import { FilterOperand } from "../core/filter/FilterOperand";
import { IBaseFilterConsumer } from "../core/filter/IBaseFilterConsumer";
-import { IBaseFilterProvider } from "../core/filter/IBaseFilterProvider";
+import { IBaseFilterProvider, instanceOfIBaseFilterProvider } from "../core/filter/IBaseFilterProvider";
import { SETTINGS_SAMPLE_SIZE, SETTINGS_X_BINS, SETTINGS_Y_BINS } from "../model/binRanges/VisualBinRangeHelper";
import { AggregateFunction, AggregateParameters, Attribute, AverageAggregateParameters, DataType, HistogramOperationParameters, QuantitativeBinRange, HistogramResult, Brush, DoubleValueAggregateResult, Bin } from "../model/idea/idea";
import { ModelHelpers } from "../model/ModelHelpers";
import { ArrayUtil } from "../utils/ArrayUtil";
import { BaseOperation } from "./BaseOperation";
+import { KeyStore } from "../../../fields/KeyStore";
+import { HistogramField } from "../dash-fields/HistogramField";
+import { FieldWaiting } from "../../../fields/Field";
export class HistogramOperation extends BaseOperation implements IBaseFilterConsumer, IBaseFilterProvider {
@observable public FilterOperand: FilterOperand = FilterOperand.AND;
@observable public Links: Document[] = [];
+ @observable public BrushLinks: Document[] = [];
@observable public BrushColors: number[] = [];
@observable public Normalization: number = -1;
@observable public FilterModels: FilterModel[] = [];
@observable public X: AttributeTransformationModel;
@observable public Y: AttributeTransformationModel;
@observable public V: AttributeTransformationModel;
- @observable public BrusherModels: BrushLinkModel[] = [];
- @observable public BrushableModels: BrushLinkModel[] = [];
@observable public SchemaName: string;
@computed public get Schema() { return CurrentUserUtils.GetNorthstarSchema(this.SchemaName); }
@@ -63,25 +64,24 @@ export class HistogramOperation extends BaseOperation implements IBaseFilterCons
@computed
public get FilterString(): string {
let filterModels: FilterModel[] = [];
- let fstring = FilterModel.GetFilterModelsRecursive(this, new Set(), filterModels, true)
- return fstring;
+ return FilterModel.GetFilterModelsRecursive(this, new Set(), filterModels, true)
}
- @computed.struct
- public get BrushString() {
- return [];
- // let brushes = [];
- // this.TypedViewModel.BrusherModels.map(brushLinkModel => {
- // if (instanceOfIBaseFilterProvider(brushLinkModel.From) && brushLinkModel.From.FilterModels.some && brushLinkModel.From instanceof BaseOperationViewModel) {
- // let brushFilterModels = [];
- // let gnode = MainManager.Instance.MainViewModel.FilterDependencyGraph.has(brushLinkModel.From) ?
- // MainManager.Instance.MainViewModel.FilterDependencyGraph.get(brushLinkModel.From) :
- // new GraphNode(brushLinkModel.From);
- // let brush = FilterModel.GetFilterModelsRecursive(gnode, new Set>(), brushFilterModels, false);
- // brushes.push(brush);
- // }
- // });
- // return brushes;
+ @computed
+ public get BrushString(): string[] {
+ let brushes: string[] = [];
+ this.BrushLinks.map(brushLink => {
+ let brusherDoc = brushLink.Get(KeyStore.LinkedFromDocs);
+ if (brusherDoc && brusherDoc != FieldWaiting && brusherDoc instanceof Document) {
+ let brushHistogram = brusherDoc.GetT(KeyStore.Data, HistogramField);
+ if (brushHistogram && brushHistogram != FieldWaiting) {
+ let filterModels: FilterModel[] = [];
+ let brush = FilterModel.GetFilterModelsRecursive(brushHistogram!.Data, new Set(), filterModels, false)
+ brushes.push(brush);
+ }
+ }
+ });
+ return brushes;
}
@@ -131,11 +131,13 @@ export class HistogramOperation extends BaseOperation implements IBaseFilterCons
});
}
}
-
+ get_random_color(): number {
+ return (Math.floor(Math.random() * 256) << 16) + (Math.floor(Math.random() * 256) << 8) + (Math.floor(Math.random() * 256));
+ }
@action
public async Update(): Promise {
- this.BrushColors = this.BrusherModels.map(e => e.Color);
+ this.BrushColors = this.BrushLinks.map(e => e.GetNumber(KeyStore.BackgroundColor, 0));
return super.Update();
}
}
--
cgit v1.2.3-70-g09d2
From 6e993fb5817e8ddce756396e53883a42530f52bb Mon Sep 17 00:00:00 2001
From: bob
Date: Fri, 29 Mar 2019 18:49:22 -0400
Subject: brushes mostly working - some problems with cycles.
---
src/client/northstar/dash-fields/HistogramField.ts | 17 +++++++-
src/client/northstar/dash-nodes/HistogramBox.tsx | 27 ++++++++----
.../dash-nodes/HistogramBoxPrimitives.tsx | 14 ++++---
src/client/northstar/operations/BaseOperation.ts | 6 ++-
.../northstar/operations/HistogramOperation.ts | 22 +++++-----
.../CollectionFreeFormLinksView.tsx | 49 +++++++++++++++++++++-
src/fields/KeyStore.ts | 1 +
7 files changed, 107 insertions(+), 29 deletions(-)
(limited to 'src/client/northstar/operations')
diff --git a/src/client/northstar/dash-fields/HistogramField.ts b/src/client/northstar/dash-fields/HistogramField.ts
index 00912c595..1929f8dcd 100644
--- a/src/client/northstar/dash-fields/HistogramField.ts
+++ b/src/client/northstar/dash-fields/HistogramField.ts
@@ -16,7 +16,8 @@ export class HistogramField extends BasicField {
}
toString(): string {
- return JSON.stringify(this.Data);
+ let omitted = this.omitKeys(this.Data, ['Links', 'BrushLinks']);
+ return JSON.stringify(omitted);
}
Copy(): Field {
@@ -27,10 +28,22 @@ export class HistogramField extends BasicField {
return `new HistogramField("${this.Data}")`;
}
+ omitKeys(obj: any, keys: any) {
+ var dup: any = {};
+ for (var key in obj) {
+ if (keys.indexOf(key) == -1) {
+ dup[key] = obj[key];
+ }
+ }
+ return dup;
+ }
+
ToJson(): { type: Types, data: string, _id: string } {
+ let omitted = this.omitKeys(this.Data, ['Links', 'BrushLinks']);
return {
type: Types.HistogramOp,
- data: JSON.stringify(this.Data),
+
+ data: JSON.stringify(omitted),
_id: this.Id
}
}
diff --git a/src/client/northstar/dash-nodes/HistogramBox.tsx b/src/client/northstar/dash-nodes/HistogramBox.tsx
index b464e125c..9976ff6ad 100644
--- a/src/client/northstar/dash-nodes/HistogramBox.tsx
+++ b/src/client/northstar/dash-nodes/HistogramBox.tsx
@@ -1,5 +1,5 @@
import React = require("react")
-import { action, computed, observable, reaction, runInAction } from "mobx";
+import { action, computed, observable, reaction, runInAction, trace } from "mobx";
import { observer } from "mobx-react";
import Measure from "react-measure";
import { FieldWaiting, Opt } from "../../../fields/Field";
@@ -8,7 +8,7 @@ import { KeyStore } from "../../../fields/KeyStore";
import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils";
import { ChartType, VisualBinRange } from '../../northstar/model/binRanges/VisualBinRange';
import { VisualBinRangeHelper } from "../../northstar/model/binRanges/VisualBinRangeHelper";
-import { AggregateBinRange, AggregateFunction, BinRange, Catalog, DoubleValueAggregateResult, HistogramResult } from "../../northstar/model/idea/idea";
+import { AggregateBinRange, AggregateFunction, BinRange, Catalog, DoubleValueAggregateResult, HistogramResult, Result } from "../../northstar/model/idea/idea";
import { ModelHelpers } from "../../northstar/model/ModelHelpers";
import { HistogramOperation } from "../../northstar/operations/HistogramOperation";
import { SizeConverter } from "../../northstar/utils/SizeConverter";
@@ -39,10 +39,10 @@ export class HistogramBox extends React.Component {
@observable public HistoOp: HistogramOperation = HistogramOperation.Empty;
@observable public VisualBinRanges: VisualBinRange[] = [];
@observable public ValueRange: number[] = [];
+ @observable public HistogramResult: HistogramResult = new HistogramResult();
@observable public SizeConverter: SizeConverter = new SizeConverter();
- @computed get createOperationParamsCache() { return this.HistoOp.CreateOperationParameters(); }
- @computed get HistogramResult() { return this.HistoOp ? this.HistoOp.Result as HistogramResult : undefined; }
+ @computed get createOperationParamsCache() { trace(); return this.HistoOp.CreateOperationParameters(); }
@computed get BinRanges() { return this.HistogramResult ? this.HistogramResult.binRanges : undefined; }
@computed get ChartType() {
return !this.BinRanges ? ChartType.SinglePoint : this.BinRanges[0] instanceof AggregateBinRange ?
@@ -123,12 +123,21 @@ export class HistogramBox extends React.Component {
this.props.doc.GetTAsync(this.props.fieldKey, HistogramField).then((histoOp: Opt) => runInAction(() => {
this.HistoOp = histoOp ? histoOp.Data : HistogramOperation.Empty;
if (this.HistoOp != HistogramOperation.Empty) {
- reaction(() => this.props.doc.GetList(KeyStore.LinkedFromDocs, []),
- (docs: Document[]) => {
+ this.HistoOp.YieldResult = (r: Result) => action(() => this.HistogramResult = r as HistogramResult)();
+ reaction(() => this.props.doc.GetList(KeyStore.LinkedFromDocs, []), (docs: Document[]) => this.HistoOp.Links.splice(0, this.HistoOp.Links.length, ...docs), { fireImmediately: true });
+ reaction(() => this.props.doc.GetList(KeyStore.BrushingDocs, []).length,
+ () => {
+ let brushingDocs = this.props.doc.GetList(KeyStore.BrushingDocs, [] as Document[]);
var availableColors = StyleConstants.BRUSH_COLORS.map(c => c);
- docs.map((brush, i) => brush.SetNumber(KeyStore.BackgroundColor, availableColors[i % availableColors.length]));
- this.HistoOp.BrushLinks.splice(0, this.HistoOp.BrushLinks.length, ...docs);
- //this.HistoOp.Links.splice(0, this.HistoOp.Links.length, ...docs)
+ let proto = this.props.doc.GetPrototype() as Document;
+ let brushingLinks = brushingDocs.map((brush, i) => {
+ // brush.SetNumber(KeyStore.BackgroundColor, availableColors[i % availableColors.length]);
+ let brushed = brush.GetList(KeyStore.BrushingDocs, [] as Document[]);
+ if (!brushed || brushed.length < 2)
+ return undefined;
+ return { l: brush, b: brushed[0].Id == proto.Id ? brushed[1] : brushed[0] }
+ }).filter(x => x != undefined) as { l: Document, b: Document }[];
+ this.HistoOp.BrushLinks.splice(0, this.HistoOp.BrushLinks.length, ...brushingLinks);
}, { fireImmediately: true });
reaction(() => this.createOperationParamsCache, () => this.HistoOp.Update(), { fireImmediately: true });
}
diff --git a/src/client/northstar/dash-nodes/HistogramBoxPrimitives.tsx b/src/client/northstar/dash-nodes/HistogramBoxPrimitives.tsx
index 648070241..c97acb064 100644
--- a/src/client/northstar/dash-nodes/HistogramBoxPrimitives.tsx
+++ b/src/client/northstar/dash-nodes/HistogramBoxPrimitives.tsx
@@ -1,5 +1,5 @@
import React = require("react")
-import { computed, observable, runInAction, reaction } from "mobx";
+import { computed, observable, runInAction, reaction, untracked, trace } from "mobx";
import { observer } from "mobx-react";
import { Utils as DashUtils } from '../../../Utils';
import { AttributeTransformationModel } from "../../northstar/core/attribute/AttributeTransformationModel";
@@ -20,7 +20,7 @@ export class HistogramBoxPrimitives extends React.Component this.props.HistoBox.HistogramResult, () => this._selectedPrims.length = 0);
+ reaction(() => this.props.HistoBox.HistoOp.FilterString, () => this._selectedPrims.length = this.histoOp.FilterModels.length = 0);
}
@observable _selectedPrims: HistogramBinPrimitive[] = [];
@computed get xaxislines() { return this.renderGridLinesAndLabels(0); }
@@ -30,10 +30,10 @@ export class HistogramBoxPrimitives extends React.Component {
let drawPrims = new HistogramBinPrimitiveCollection(histoResult!.bins![key], this.props.HistoBox);
-
let toggle = this.getSelectionToggle(drawPrims.BinPrimitives, allBrushIndex,
ModelHelpers.GetBinFilterModel(histoResult!.bins![key], allBrushIndex, histoResult!, this.histoOp.X, this.histoOp.Y));
drawPrims.BinPrimitives.filter(bp => bp.DataValue && bp.BrushIndex !== allBrushIndex).map(bp =>
@@ -327,6 +327,7 @@ export class HistogramBinPrimitiveCollection {
}
private baseColorFromBrush(brush: Brush): number {
+ let bc = StyleConstants.BRUSH_COLORS;
if (brush.brushIndex == ModelHelpers.RestBrushIndex(this.histoResult)) {
return StyleConstants.HIGHLIGHT_COLOR;
}
@@ -336,9 +337,12 @@ export class HistogramBinPrimitiveCollection {
else if (brush.brushIndex == ModelHelpers.AllBrushIndex(this.histoResult)) {
return 0x00ff00;
}
- else if (this.histoOp.BrushColors.length > 0) {
- return this.histoOp.BrushColors[brush.brushIndex! % this.histoOp.BrushColors.length];
+ else if (bc.length > 0) {
+ return bc[brush.brushIndex! % bc.length];
}
+ // else if (this.histoOp.BrushColors.length > 0) {
+ // return this.histoOp.BrushColors[brush.brushIndex! % this.histoOp.BrushColors.length];
+ // }
return StyleConstants.HIGHLIGHT_COLOR;
}
}
\ No newline at end of file
diff --git a/src/client/northstar/operations/BaseOperation.ts b/src/client/northstar/operations/BaseOperation.ts
index 94e0849af..21d1db749 100644
--- a/src/client/northstar/operations/BaseOperation.ts
+++ b/src/client/northstar/operations/BaseOperation.ts
@@ -10,7 +10,8 @@ export abstract class BaseOperation {
@observable public Error: string = "";
@observable public OverridingFilters: FilterModel[] = [];
- @observable public Result?: Result = undefined;
+ //@observable
+ public Result?: Result = undefined;
@observable public ComputationStarted: boolean = false;
public OperationReference?: OperationReference = undefined;
@@ -45,8 +46,11 @@ export abstract class BaseOperation {
}
+ public YieldResult: ((result: Result) => void) | undefined;
@action
public SetResult(result: Result): void {
+ if (this.YieldResult)
+ this.YieldResult(result);
this.Result = result;
}
diff --git a/src/client/northstar/operations/HistogramOperation.ts b/src/client/northstar/operations/HistogramOperation.ts
index fa51e2a8c..48bad73df 100644
--- a/src/client/northstar/operations/HistogramOperation.ts
+++ b/src/client/northstar/operations/HistogramOperation.ts
@@ -1,4 +1,4 @@
-import { action, computed, observable } from "mobx";
+import { action, computed, observable, trace } from "mobx";
import { Document } from "../../../fields/Document";
import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils";
import { ColumnAttributeModel } from "../core/attribute/AttributeModel";
@@ -16,12 +16,13 @@ import { BaseOperation } from "./BaseOperation";
import { KeyStore } from "../../../fields/KeyStore";
import { HistogramField } from "../dash-fields/HistogramField";
import { FieldWaiting } from "../../../fields/Field";
+import { StyleConstants } from "../utils/StyleContants";
export class HistogramOperation extends BaseOperation implements IBaseFilterConsumer, IBaseFilterProvider {
@observable public FilterOperand: FilterOperand = FilterOperand.AND;
@observable public Links: Document[] = [];
- @observable public BrushLinks: Document[] = [];
+ @observable public BrushLinks: { l: Document, b: Document }[] = [];
@observable public BrushColors: number[] = [];
@observable public Normalization: number = -1;
@observable public FilterModels: FilterModel[] = [];
@@ -69,16 +70,15 @@ export class HistogramOperation extends BaseOperation implements IBaseFilterCons
@computed
public get BrushString(): string[] {
+ trace();
let brushes: string[] = [];
this.BrushLinks.map(brushLink => {
- let brusherDoc = brushLink.Get(KeyStore.LinkedFromDocs);
- if (brusherDoc && brusherDoc != FieldWaiting && brusherDoc instanceof Document) {
- let brushHistogram = brusherDoc.GetT(KeyStore.Data, HistogramField);
- if (brushHistogram && brushHistogram != FieldWaiting) {
- let filterModels: FilterModel[] = [];
- let brush = FilterModel.GetFilterModelsRecursive(brushHistogram!.Data, new Set(), filterModels, false)
- brushes.push(brush);
- }
+ let brusherDoc = brushLink.b;
+ let brushHistogram = brusherDoc.GetT(KeyStore.Data, HistogramField);
+ if (brushHistogram && brushHistogram != FieldWaiting) {
+ let filterModels: FilterModel[] = [];
+ let brush = FilterModel.GetFilterModelsRecursive(brushHistogram!.Data, new Set(), filterModels, false)
+ brushes.push(brush);
}
});
return brushes;
@@ -137,7 +137,7 @@ export class HistogramOperation extends BaseOperation implements IBaseFilterCons
@action
public async Update(): Promise {
- this.BrushColors = this.BrushLinks.map(e => e.GetNumber(KeyStore.BackgroundColor, 0));
+ //this.BrushColors = this.BrushLinks.map(e => e.l.GetNumber(KeyStore.BackgroundColor, 0));
return super.Update();
}
}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
index 4f28f43eb..8dbf80533 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
@@ -1,4 +1,4 @@
-import { computed } from "mobx";
+import { computed, reaction, runInAction } from "mobx";
import { observer } from "mobx-react";
import { Document } from "../../../../fields/Document";
import { FieldWaiting } from "../../../../fields/Field";
@@ -11,10 +11,57 @@ import "./CollectionFreeFormLinksView.scss";
import React = require("react");
import v5 = require("uuid/v5");
import { CollectionFreeFormLinkView } from "./CollectionFreeFormLinkView";
+import { ListField } from "../../../../fields/ListField";
+import { TextField } from "../../../../fields/TextField";
+import { StyleConstants } from "../../../northstar/utils/StyleContants";
@observer
export class CollectionFreeFormLinksView extends React.Component {
+ componentDidMount() {
+ reaction(() => {
+ return DocumentManager.Instance.getAllDocumentViews(this.props.Document).map(dv => dv.props.Document.GetNumber(KeyStore.X, 0))
+ }, () => {
+ let views = DocumentManager.Instance.getAllDocumentViews(this.props.Document);
+ for (let i = 0; i < views.length; i++) {
+ for (let j = i + 1; j < views.length; j++) {
+ let srcDoc = views[j].props.Document;
+ let dstDoc = views[i].props.Document;
+ let x1 = srcDoc.GetNumber(KeyStore.X, 0);
+ let x1w = srcDoc.GetNumber(KeyStore.Width, 0);
+ let x2 = dstDoc.GetNumber(KeyStore.X, 0);
+ let x2w = dstDoc.GetNumber(KeyStore.Width, 0);
+ if (Math.abs(x1 + x1w - x2) < 20 || Math.abs(x2 + x2w - x1) < 20) {
+ let linkDoc: Document = new Document();
+ dstDoc.GetTAsync(KeyStore.Prototype, Document).then((protoDest) =>
+ srcDoc.GetTAsync(KeyStore.Prototype, Document).then((protoSrc) => runInAction(() => {
+ linkDoc.Set(KeyStore.Title, new TextField("New Brush"));
+ linkDoc.Set(KeyStore.LinkDescription, new TextField(""));
+ linkDoc.Set(KeyStore.LinkTags, new TextField("Default"));
+ linkDoc.SetNumber(KeyStore.BackgroundColor, StyleConstants.BRUSH_COLORS[0]);
+
+ let dstTarg = (protoDest ? protoDest : dstDoc);
+ let srcTarg = (protoSrc ? protoSrc : srcDoc);
+ linkDoc.SetData(KeyStore.BrushingDocs, [dstTarg, srcTarg], ListField);
+ dstTarg.GetOrCreateAsync(KeyStore.BrushingDocs, ListField, field => { (field as ListField).Data.push(linkDoc) })
+ srcTarg.GetOrCreateAsync(KeyStore.BrushingDocs, ListField, field => { (field as ListField).Data.push(linkDoc) })
+ }))
+ )
+ } else {
+ dstDoc.GetTAsync(KeyStore.Prototype, Document).then((protoDest) =>
+ srcDoc.GetTAsync(KeyStore.Prototype, Document).then((protoSrc) => runInAction(() => {
+
+ let dstTarg = (protoDest ? protoDest : dstDoc);
+ let srcTarg = (protoSrc ? protoSrc : srcDoc);
+ dstTarg.GetOrCreateAsync(KeyStore.BrushingDocs, ListField, field => { (field as ListField).Data.length = 0 })
+ srcTarg.GetOrCreateAsync(KeyStore.BrushingDocs, ListField, field => { (field as ListField).Data.length = 0 })
+ }))
+ )
+ }
+ }
+ }
+ });
+ }
documentAnchors(view: DocumentView) {
let equalViews = [view];
let containerDoc = view.props.Document.GetT(KeyStore.AnnotationOn, Document);
diff --git a/src/fields/KeyStore.ts b/src/fields/KeyStore.ts
index aa0b9ce92..1f039e592 100644
--- a/src/fields/KeyStore.ts
+++ b/src/fields/KeyStore.ts
@@ -29,6 +29,7 @@ export namespace KeyStore {
export const Caption = new Key("Caption");
export const ActiveWorkspace = new Key("ActiveWorkspace");
export const DocumentText = new Key("DocumentText");
+ export const BrushingDocs = new Key("BrushingDocs");
export const LinkedToDocs = new Key("LinkedToDocs");
export const LinkedFromDocs = new Key("LinkedFromDocs");
export const LinkDescription = new Key("LinkDescription");
--
cgit v1.2.3-70-g09d2
From 79f9bc805f281a13fe59162f2e25dd1fdcefaae0 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik
Date: Fri, 29 Mar 2019 20:13:06 -0400
Subject: code cleanup
---
src/client/northstar/dash-fields/HistogramField.ts | 24 +-
.../dash-nodes/HistogramBinPrimitiveCollection.ts | 238 ++++++++++++++++++++
src/client/northstar/dash-nodes/HistogramBox.tsx | 21 +-
.../dash-nodes/HistogramBoxPrimitives.scss | 4 +
.../dash-nodes/HistogramBoxPrimitives.tsx | 246 +--------------------
.../dash-nodes/HistogramLabelPrimitives.tsx | 3 +-
.../northstar/operations/HistogramOperation.ts | 73 +++---
7 files changed, 301 insertions(+), 308 deletions(-)
create mode 100644 src/client/northstar/dash-nodes/HistogramBinPrimitiveCollection.ts
(limited to 'src/client/northstar/operations')
diff --git a/src/client/northstar/dash-fields/HistogramField.ts b/src/client/northstar/dash-fields/HistogramField.ts
index 1929f8dcd..ae83ea5ba 100644
--- a/src/client/northstar/dash-fields/HistogramField.ts
+++ b/src/client/northstar/dash-fields/HistogramField.ts
@@ -15,9 +15,17 @@ export class HistogramField extends BasicField {
super(data ? data : HistogramOperation.Empty, save, id);
}
+ omitKeys(obj: any, keys: any) {
+ var dup: any = {};
+ for (var key in obj) {
+ if (keys.indexOf(key) == -1) {
+ dup[key] = obj[key];
+ }
+ }
+ return dup;
+ }
toString(): string {
- let omitted = this.omitKeys(this.Data, ['Links', 'BrushLinks']);
- return JSON.stringify(omitted);
+ return JSON.stringify(this.omitKeys(this.Data, ['Links', 'BrushLinks', 'Result']));
}
Copy(): Field {
@@ -28,22 +36,12 @@ export class HistogramField extends BasicField {
return `new HistogramField("${this.Data}")`;
}
- omitKeys(obj: any, keys: any) {
- var dup: any = {};
- for (var key in obj) {
- if (keys.indexOf(key) == -1) {
- dup[key] = obj[key];
- }
- }
- return dup;
- }
ToJson(): { type: Types, data: string, _id: string } {
- let omitted = this.omitKeys(this.Data, ['Links', 'BrushLinks']);
return {
type: Types.HistogramOp,
- data: JSON.stringify(omitted),
+ data: this.toString(),
_id: this.Id
}
}
diff --git a/src/client/northstar/dash-nodes/HistogramBinPrimitiveCollection.ts b/src/client/northstar/dash-nodes/HistogramBinPrimitiveCollection.ts
new file mode 100644
index 000000000..43e768c62
--- /dev/null
+++ b/src/client/northstar/dash-nodes/HistogramBinPrimitiveCollection.ts
@@ -0,0 +1,238 @@
+import React = require("react")
+import { AttributeTransformationModel } from "../../northstar/core/attribute/AttributeTransformationModel";
+import { ChartType } from '../../northstar/model/binRanges/VisualBinRange';
+import { AggregateFunction, Bin, Brush, DoubleValueAggregateResult, HistogramResult, MarginAggregateParameters, MarginAggregateResult } from "../../northstar/model/idea/idea";
+import { ModelHelpers } from "../../northstar/model/ModelHelpers";
+import { LABColor } from '../../northstar/utils/LABcolor';
+import { PIXIRectangle } from "../../northstar/utils/MathUtil";
+import { StyleConstants } from "../../northstar/utils/StyleContants";
+import { HistogramBox } from "./HistogramBox";
+import "./HistogramBoxPrimitives.scss";
+
+export class HistogramBinPrimitive {
+ constructor(init?: Partial) {
+ Object.assign(this, init);
+ }
+ public DataValue: number = 0;
+ public Rect: PIXIRectangle = PIXIRectangle.EMPTY;
+ public MarginRect: PIXIRectangle = PIXIRectangle.EMPTY;
+ public MarginPercentage: number = 0;
+ public Color: number = StyleConstants.WARNING_COLOR;
+ public Opacity: number = 1;
+ public BrushIndex: number = 0;
+ public BarAxis: number = -1;
+}
+
+export class HistogramBinPrimitiveCollection {
+ private static TOLERANCE: number = 0.0001;
+
+ private _histoBox: HistogramBox;
+ private get histoOp() { return this._histoBox.HistoOp; }
+ private get histoResult() { return this.histoOp.Result as HistogramResult; }
+ private get sizeConverter() { return this._histoBox.SizeConverter!; }
+ public BinPrimitives: Array = new Array();
+ public HitGeom: PIXIRectangle = PIXIRectangle.EMPTY;
+
+ constructor(bin: Bin, histoBox: HistogramBox) {
+ this._histoBox = histoBox;
+ let brushing = this.setupBrushing(bin, this.histoOp.Normalization); // X= 0, Y = 1, V = 2
+
+ brushing.orderedBrushes.reduce((brushFactorSum, brush) => {
+ switch (histoBox.ChartType) {
+ case ChartType.VerticalBar: return this.createVerticalBarChartBinPrimitives(bin, brush, brushing.maxAxis, this.histoOp.Normalization);
+ case ChartType.HorizontalBar: return this.createHorizontalBarChartBinPrimitives(bin, brush, brushing.maxAxis, this.histoOp.Normalization);
+ case ChartType.SinglePoint: return this.createSinglePointChartBinPrimitives(bin, brush);
+ case ChartType.HeatMap: return this.createHeatmapBinPrimitives(bin, brush, brushFactorSum);
+ }
+ }, 0);
+
+ // adjust brush rects (stacking or not)
+ var allBrushIndex = ModelHelpers.AllBrushIndex(this.histoResult);
+ var filteredBinPrims = this.BinPrimitives.filter(b => b.BrushIndex != allBrushIndex && b.DataValue != 0.0);
+ filteredBinPrims.reduce((sum, fbp) => {
+ if (histoBox.ChartType == ChartType.VerticalBar) {
+ if (this.histoOp.Y.AggregateFunction == AggregateFunction.Count) {
+ fbp.Rect = new PIXIRectangle(fbp.Rect.x, fbp.Rect.y - sum, fbp.Rect.width, fbp.Rect.height);
+ fbp.MarginRect = new PIXIRectangle(fbp.MarginRect.x, fbp.MarginRect.y - sum, fbp.MarginRect.width, fbp.MarginRect.height);
+ return sum + fbp.Rect.height;
+ }
+ if (this.histoOp.Y.AggregateFunction == AggregateFunction.Avg) {
+ var w = fbp.Rect.width / 2.0;
+ fbp.Rect = new PIXIRectangle(fbp.Rect.x + sum, fbp.Rect.y, fbp.Rect.width / filteredBinPrims.length, fbp.Rect.height);
+ fbp.MarginRect = new PIXIRectangle(fbp.MarginRect.x - w + sum + (fbp.Rect.width / 2.0), fbp.MarginRect.y, fbp.MarginRect.width, fbp.MarginRect.height);
+ return sum + fbp.Rect.width;
+ }
+ }
+ else if (histoBox.ChartType == ChartType.HorizontalBar) {
+ if (this.histoOp.X.AggregateFunction == AggregateFunction.Count) {
+ fbp.Rect = new PIXIRectangle(fbp.Rect.x + sum, fbp.Rect.y, fbp.Rect.width, fbp.Rect.height);
+ fbp.MarginRect = new PIXIRectangle(fbp.MarginRect.x + sum, fbp.MarginRect.y, fbp.MarginRect.width, fbp.MarginRect.height);
+ return sum + fbp.Rect.width;
+ }
+ if (this.histoOp.X.AggregateFunction == AggregateFunction.Avg) {
+ var h = fbp.Rect.height / 2.0;
+ fbp.Rect = new PIXIRectangle(fbp.Rect.x, fbp.Rect.y + sum, fbp.Rect.width, fbp.Rect.height / filteredBinPrims.length);
+ fbp.MarginRect = new PIXIRectangle(fbp.MarginRect.x, fbp.MarginRect.y - h + sum + (fbp.Rect.height / 2.0), fbp.MarginRect.width, fbp.MarginRect.height);
+ return sum + fbp.Rect.height;
+ }
+ }
+ return 0;
+ }, 0);
+ this.BinPrimitives = this.BinPrimitives.reverse();
+ var f = this.BinPrimitives.filter(b => b.BrushIndex == allBrushIndex);
+ this.HitGeom = f.length > 0 ? f[0].Rect : PIXIRectangle.EMPTY;
+ }
+
+ private setupBrushing(bin: Bin, normalization: number) {
+ var overlapBrushIndex = ModelHelpers.OverlapBrushIndex(this.histoResult);
+ var orderedBrushes = [this.histoResult.brushes![0], this.histoResult.brushes![overlapBrushIndex]];
+ this.histoResult.brushes!.map(brush => brush.brushIndex != 0 && brush.brushIndex != overlapBrushIndex && orderedBrushes.push(brush));
+ return {
+ orderedBrushes,
+ maxAxis: orderedBrushes.reduce((prev, Brush) => {
+ let aggResult = this.getBinValue(normalization, bin, Brush.brushIndex!);
+ return aggResult != undefined && aggResult > prev ? aggResult : prev;
+ }, Number.MIN_VALUE)
+ };
+ }
+
+ private createHeatmapBinPrimitives(bin: Bin, brush: Brush, brushFactorSum: number): number {
+
+ let unNormalizedValue = this.getBinValue(2, bin, brush.brushIndex!);
+ if (unNormalizedValue == undefined)
+ return brushFactorSum;
+
+ var normalizedValue = (unNormalizedValue - this._histoBox.ValueRange[0]) / (Math.abs((this._histoBox.ValueRange[1] - this._histoBox.ValueRange[0])) < HistogramBinPrimitiveCollection.TOLERANCE ?
+ unNormalizedValue : this._histoBox.ValueRange[1] - this._histoBox.ValueRange[0]);
+
+ let allUnNormalizedValue = this.getBinValue(2, bin, ModelHelpers.AllBrushIndex(this.histoResult))
+
+ // bcz: are these calls needed?
+ let [xFrom, xTo] = this.sizeConverter.DataToScreenXAxisRange(this._histoBox.VisualBinRanges, 0, bin);
+ let [yFrom, yTo] = this.sizeConverter.DataToScreenYAxisRange(this._histoBox.VisualBinRanges, 1, bin);
+
+ var returnBrushFactorSum = brushFactorSum;
+ if (allUnNormalizedValue != undefined) {
+ var brushFactor = (unNormalizedValue / allUnNormalizedValue);
+ returnBrushFactorSum += brushFactor;
+ returnBrushFactorSum = Math.min(returnBrushFactorSum, 1.0);
+
+ var tempRect = new PIXIRectangle(xFrom, yTo, xTo - xFrom, yFrom - yTo);
+ var ratio = (tempRect.width / tempRect.height);
+ var newHeight = Math.sqrt((1.0 / ratio) * ((tempRect.width * tempRect.height) * returnBrushFactorSum));
+ var newWidth = newHeight * ratio;
+
+ xFrom = (tempRect.x + (tempRect.width - newWidth) / 2.0);
+ yTo = (tempRect.y + (tempRect.height - newHeight) / 2.0);
+ xTo = (xFrom + newWidth);
+ yFrom = (yTo + newHeight);
+ }
+ var alpha = 0.0;
+ var color = this.baseColorFromBrush(brush);
+ var lerpColor = LABColor.Lerp(
+ LABColor.FromColor(StyleConstants.MIN_VALUE_COLOR),
+ LABColor.FromColor(color),
+ (alpha + Math.pow(normalizedValue, 1.0 / 3.0) * (1.0 - alpha)));
+ var dataColor = LABColor.ToColor(lerpColor);
+
+ this.createBinPrimitive(-1, brush, PIXIRectangle.EMPTY, 0, xFrom, xTo, yFrom, yTo, dataColor, 1, unNormalizedValue);
+ return returnBrushFactorSum;
+ }
+
+ private createSinglePointChartBinPrimitives(bin: Bin, brush: Brush): number {
+ let unNormalizedValue = this.getBinValue(2, bin, brush.brushIndex!);
+ if (unNormalizedValue != undefined) {
+ let [xFrom, xTo] = this.sizeConverter.DataToScreenPointRange(0, bin, ModelHelpers.CreateAggregateKey(this.histoOp.Schema!.distinctAttributeParameters, this.histoOp.X, this.histoResult, brush.brushIndex!));
+ let [yFrom, yTo] = this.sizeConverter.DataToScreenPointRange(1, bin, ModelHelpers.CreateAggregateKey(this.histoOp.Schema!.distinctAttributeParameters, this.histoOp.Y, this.histoResult, brush.brushIndex!));
+
+ if (xFrom != undefined && yFrom != undefined && xTo != undefined && yTo != undefined)
+ this.createBinPrimitive(-1, brush, PIXIRectangle.EMPTY, 0, xFrom, xTo, yFrom, yTo, this.baseColorFromBrush(brush), 1, unNormalizedValue);
+ }
+ return 0;
+ }
+
+ private createVerticalBarChartBinPrimitives(bin: Bin, brush: Brush, binBrushMaxAxis: number, normalization: number): number {
+ let dataValue = this.getBinValue(1, bin, brush.brushIndex!);
+ if (dataValue != undefined) {
+ let [yFrom, yValue, yTo] = this.sizeConverter.DataToScreenNormalizedRange(dataValue, normalization, 1, binBrushMaxAxis);
+ let [xFrom, xTo] = this.sizeConverter.DataToScreenXAxisRange(this._histoBox.VisualBinRanges, 0, bin);
+
+ var yMarginAbsolute = this.getMargin(bin, brush, this.histoOp.Y);
+ var marginRect = new PIXIRectangle(xFrom + (xTo - xFrom) / 2.0 - 1,
+ this.sizeConverter.DataToScreenY(yValue + yMarginAbsolute), 2,
+ this.sizeConverter.DataToScreenY(yValue - yMarginAbsolute) - this.sizeConverter.DataToScreenY(yValue + yMarginAbsolute));
+
+ this.createBinPrimitive(1, brush, marginRect, 0, xFrom, xTo, yFrom, yTo,
+ this.baseColorFromBrush(brush), normalization != 0 ? 1 : 0.6 * binBrushMaxAxis / this.sizeConverter.DataRanges[1] + 0.4, dataValue);
+ }
+ return 0;
+ }
+
+ private createHorizontalBarChartBinPrimitives(bin: Bin, brush: Brush, binBrushMaxAxis: number, normalization: number): number {
+ let dataValue = this.getBinValue(0, bin, brush.brushIndex!);
+ if (dataValue != undefined) {
+ let [xFrom, xValue, xTo] = this.sizeConverter.DataToScreenNormalizedRange(dataValue, normalization, 0, binBrushMaxAxis);
+ let [yFrom, yTo] = this.sizeConverter.DataToScreenYAxisRange(this._histoBox.VisualBinRanges, 1, bin);
+
+ var xMarginAbsolute = this.sizeConverter.IsSmall ? 0 : this.getMargin(bin, brush, this.histoOp.X);
+ var marginRect = new PIXIRectangle(this.sizeConverter.DataToScreenX(xValue - xMarginAbsolute),
+ yTo + (yFrom - yTo) / 2.0 - 1,
+ this.sizeConverter.DataToScreenX(xValue + xMarginAbsolute) - this.sizeConverter.DataToScreenX(xValue - xMarginAbsolute),
+ 2.0);
+
+ this.createBinPrimitive(0, brush, marginRect, 0, xFrom, xTo, yFrom, yTo,
+ this.baseColorFromBrush(brush), normalization != 1 ? 1 : 0.6 * binBrushMaxAxis / this.sizeConverter.DataRanges[0] + 0.4, dataValue);
+ }
+ return 0;
+ }
+
+ public getBinValue(axis: number, bin: Bin, brushIndex: number) {
+ var aggregateKey = ModelHelpers.CreateAggregateKey(this.histoOp.Schema!.distinctAttributeParameters, axis == 0 ? this.histoOp.X : axis == 1 ? this.histoOp.Y : this.histoOp.V, this.histoResult, brushIndex);
+ let dataValue = ModelHelpers.GetAggregateResult(bin, aggregateKey) as DoubleValueAggregateResult;
+ return dataValue != null && dataValue.hasResult ? dataValue.result : undefined;
+ }
+
+ private getMargin(bin: Bin, brush: Brush, axis: AttributeTransformationModel) {
+ var marginParams = new MarginAggregateParameters();
+ marginParams.aggregateFunction = axis.AggregateFunction;
+ var marginAggregateKey = ModelHelpers.CreateAggregateKey(this.histoOp.Schema!.distinctAttributeParameters, axis, this.histoResult, brush.brushIndex!, marginParams);
+ var marginResult = ModelHelpers.GetAggregateResult(bin, marginAggregateKey) as MarginAggregateResult;
+ return !marginResult ? 0 : marginResult.absolutMargin!;
+ }
+
+ private createBinPrimitive(barAxis: number, brush: Brush, marginRect: PIXIRectangle,
+ marginPercentage: number, xFrom: number, xTo: number, yFrom: number, yTo: number, color: number, opacity: number, dataValue: number) {
+ var binPrimitive = new HistogramBinPrimitive(
+ {
+ Rect: new PIXIRectangle(xFrom, yTo, xTo - xFrom, yFrom - yTo),
+ MarginRect: marginRect,
+ MarginPercentage: marginPercentage,
+ BrushIndex: brush.brushIndex,
+ Color: color,
+ Opacity: opacity,
+ DataValue: dataValue,
+ BarAxis: barAxis
+ });
+ this.BinPrimitives.push(binPrimitive);
+ }
+
+ private baseColorFromBrush(brush: Brush): number {
+ let bc = StyleConstants.BRUSH_COLORS;
+ if (brush.brushIndex == ModelHelpers.RestBrushIndex(this.histoResult)) {
+ return StyleConstants.HIGHLIGHT_COLOR;
+ }
+ else if (brush.brushIndex == ModelHelpers.OverlapBrushIndex(this.histoResult)) {
+ return StyleConstants.OVERLAP_COLOR;
+ }
+ else if (brush.brushIndex == ModelHelpers.AllBrushIndex(this.histoResult)) {
+ return 0x00ff00;
+ }
+ else if (bc.length > 0) {
+ return bc[brush.brushIndex! % bc.length];
+ }
+ // else if (this.histoOp.BrushColors.length > 0) {
+ // return this.histoOp.BrushColors[brush.brushIndex! % this.histoOp.BrushColors.length];
+ // }
+ return StyleConstants.HIGHLIGHT_COLOR;
+ }
+}
\ No newline at end of file
diff --git a/src/client/northstar/dash-nodes/HistogramBox.tsx b/src/client/northstar/dash-nodes/HistogramBox.tsx
index 9976ff6ad..6bf2697fc 100644
--- a/src/client/northstar/dash-nodes/HistogramBox.tsx
+++ b/src/client/northstar/dash-nodes/HistogramBox.tsx
@@ -22,9 +22,6 @@ import { HistogramBoxPrimitives } from './HistogramBoxPrimitives';
import { HistogramLabelPrimitives } from "./HistogramLabelPrimitives";
import { StyleConstants } from "../utils/StyleContants";
-export interface HistogramPrimitivesProps {
- HistoBox: HistogramBox;
-}
@observer
export class HistogramBox extends React.Component {
@@ -77,6 +74,15 @@ export class HistogramBox extends React.Component {
}
}
+ @action
+ xLabelPointerDown = (e: React.PointerEvent) => {
+ this.HistoOp.X = new AttributeTransformationModel(this.HistoOp.X.AttributeModel, this.HistoOp.X.AggregateFunction == AggregateFunction.None ? AggregateFunction.Count : AggregateFunction.None);
+ }
+ @action
+ yLabelPointerDown = (e: React.PointerEvent) => {
+ this.HistoOp.Y = new AttributeTransformationModel(this.HistoOp.Y.AttributeModel, this.HistoOp.Y.AggregateFunction == AggregateFunction.None ? AggregateFunction.Count : AggregateFunction.None);
+ }
+
componentDidMount() {
if (this._dropXRef.current) {
this._dropXDisposer = DragManager.MakeDropTarget(this._dropXRef.current, { handlers: { drop: this.dropX.bind(this) } });
@@ -102,15 +108,6 @@ export class HistogramBox extends React.Component {
});
}
- @action
- xLabelPointerDown = (e: React.PointerEvent) => {
- this.HistoOp.X = new AttributeTransformationModel(this.HistoOp.X.AttributeModel, this.HistoOp.X.AggregateFunction == AggregateFunction.None ? AggregateFunction.Count : AggregateFunction.None);
- }
- @action
- yLabelPointerDown = (e: React.PointerEvent) => {
- this.HistoOp.Y = new AttributeTransformationModel(this.HistoOp.Y.AttributeModel, this.HistoOp.Y.AggregateFunction == AggregateFunction.None ? AggregateFunction.Count : AggregateFunction.None);
- }
-
componentWillUnmount() {
if (this._dropXDisposer)
this._dropXDisposer();
diff --git a/src/client/northstar/dash-nodes/HistogramBoxPrimitives.scss b/src/client/northstar/dash-nodes/HistogramBoxPrimitives.scss
index 9d42219cc..ce9edd65e 100644
--- a/src/client/northstar/dash-nodes/HistogramBoxPrimitives.scss
+++ b/src/client/northstar/dash-nodes/HistogramBoxPrimitives.scss
@@ -1,3 +1,7 @@
+.histogramboxprimitives-container {
+ width: 100%;
+ height: 100%;
+}
.histogramboxprimitives-border {
border: 3px;
border-style: solid;
diff --git a/src/client/northstar/dash-nodes/HistogramBoxPrimitives.tsx b/src/client/northstar/dash-nodes/HistogramBoxPrimitives.tsx
index c97acb064..e9adb3ce5 100644
--- a/src/client/northstar/dash-nodes/HistogramBoxPrimitives.tsx
+++ b/src/client/northstar/dash-nodes/HistogramBoxPrimitives.tsx
@@ -1,27 +1,24 @@
import React = require("react")
-import { computed, observable, runInAction, reaction, untracked, trace } from "mobx";
+import { computed, observable, reaction, runInAction, trace } from "mobx";
import { observer } from "mobx-react";
import { Utils as DashUtils } from '../../../Utils';
-import { AttributeTransformationModel } from "../../northstar/core/attribute/AttributeTransformationModel";
import { FilterModel } from "../../northstar/core/filter/FilterModel";
-import { ChartType } from '../../northstar/model/binRanges/VisualBinRange';
-import { AggregateFunction, Bin, Brush, HistogramResult, MarginAggregateParameters, MarginAggregateResult } from "../../northstar/model/idea/idea";
import { ModelHelpers } from "../../northstar/model/ModelHelpers";
import { ArrayUtil } from "../../northstar/utils/ArrayUtil";
import { LABColor } from '../../northstar/utils/LABcolor';
import { PIXIRectangle } from "../../northstar/utils/MathUtil";
import { StyleConstants } from "../../northstar/utils/StyleContants";
-import { HistogramBox, HistogramPrimitivesProps } from "./HistogramBox";
+import { HistogramBinPrimitiveCollection, HistogramBinPrimitive } from "./HistogramBinPrimitiveCollection";
+import { HistogramBox } from "./HistogramBox";
import "./HistogramBoxPrimitives.scss";
-
+export interface HistogramPrimitivesProps {
+ HistoBox: HistogramBox;
+}
@observer
export class HistogramBoxPrimitives extends React.Component {
private get histoOp() { return this.props.HistoBox.HistoOp; }
private get renderDimension() { return this.props.HistoBox.SizeConverter.RenderDimension; }
- componentDidMount() {
- reaction(() => this.props.HistoBox.HistoOp.FilterString, () => this._selectedPrims.length = this.histoOp.FilterModels.length = 0);
- }
@observable _selectedPrims: HistogramBinPrimitive[] = [];
@computed get xaxislines() { return this.renderGridLinesAndLabels(0); }
@computed get yaxislines() { return this.renderGridLinesAndLabels(1); }
@@ -42,6 +39,10 @@ export class HistogramBoxPrimitives extends React.Component this.props.HistoBox.HistoOp.FilterString, () => this._selectedPrims.length = this.histoOp.FilterModels.length = 0);
+ }
+
private getSelectionToggle(binPrimitives: HistogramBinPrimitive[], allBrushIndex: number, filterModel: FilterModel) {
let allBrushPrim = ArrayUtil.FirstOrDefault(binPrimitives, bp => bp.BrushIndex == allBrushIndex);
return !allBrushPrim ? () => { } : () => runInAction(() => {
@@ -90,7 +91,6 @@ export class HistogramBoxPrimitives extends React.Component);
return this.drawEntity(xFrom, yFrom, line);
}
-
drawRect(r: PIXIRectangle, barAxis: number, color: number | undefined, classExt: string, tapHandler: () => void = () => { }) {
if (r.height < 0) {
r.y += r.height;
@@ -114,235 +114,11 @@ export class HistogramBoxPrimitives extends React.Component
+ return
{this.xaxislines}
{this.yaxislines}
{this.binPrimitives}
{this.selectedPrimitives}
}
-}
-
-class HistogramBinPrimitive {
- constructor(init?: Partial) {
- Object.assign(this, init);
- }
- public DataValue: number = 0;
- public Rect: PIXIRectangle = PIXIRectangle.EMPTY;
- public MarginRect: PIXIRectangle = PIXIRectangle.EMPTY;
- public MarginPercentage: number = 0;
- public Color: number = StyleConstants.WARNING_COLOR;
- public Opacity: number = 1;
- public BrushIndex: number = 0;
- public BarAxis: number = -1;
-}
-
-export class HistogramBinPrimitiveCollection {
- private static TOLERANCE: number = 0.0001;
-
- private _histoBox: HistogramBox;
- private get histoOp() { return this._histoBox.HistoOp; }
- private get histoResult() { return this.histoOp.Result as HistogramResult; }
- private get sizeConverter() { return this._histoBox.SizeConverter!; }
- public BinPrimitives: Array = new Array();
- public HitGeom: PIXIRectangle = PIXIRectangle.EMPTY;
-
- constructor(bin: Bin, histoBox: HistogramBox) {
- this._histoBox = histoBox;
- let brushing = this.setupBrushing(bin, this.histoOp.Normalization); // X= 0, Y = 1, V = 2
-
- brushing.orderedBrushes.reduce((brushFactorSum, brush) => {
- switch (histoBox.ChartType) {
- case ChartType.VerticalBar: return this.createVerticalBarChartBinPrimitives(bin, brush, brushing.maxAxis, this.histoOp.Normalization);
- case ChartType.HorizontalBar: return this.createHorizontalBarChartBinPrimitives(bin, brush, brushing.maxAxis, this.histoOp.Normalization);
- case ChartType.SinglePoint: return this.createSinglePointChartBinPrimitives(bin, brush);
- case ChartType.HeatMap: return this.createHeatmapBinPrimitives(bin, brush, brushFactorSum);
- }
- }, 0);
-
- // adjust brush rects (stacking or not)
- var allBrushIndex = ModelHelpers.AllBrushIndex(this.histoResult);
- var filteredBinPrims = this.BinPrimitives.filter(b => b.BrushIndex != allBrushIndex && b.DataValue != 0.0);
- filteredBinPrims.reduce((sum, fbp) => {
- if (histoBox.ChartType == ChartType.VerticalBar) {
- if (this.histoOp.Y.AggregateFunction == AggregateFunction.Count) {
- fbp.Rect = new PIXIRectangle(fbp.Rect.x, fbp.Rect.y - sum, fbp.Rect.width, fbp.Rect.height);
- fbp.MarginRect = new PIXIRectangle(fbp.MarginRect.x, fbp.MarginRect.y - sum, fbp.MarginRect.width, fbp.MarginRect.height);
- return sum + fbp.Rect.height;
- }
- if (this.histoOp.Y.AggregateFunction == AggregateFunction.Avg) {
- var w = fbp.Rect.width / 2.0;
- fbp.Rect = new PIXIRectangle(fbp.Rect.x + sum, fbp.Rect.y, fbp.Rect.width / filteredBinPrims.length, fbp.Rect.height);
- fbp.MarginRect = new PIXIRectangle(fbp.MarginRect.x - w + sum + (fbp.Rect.width / 2.0), fbp.MarginRect.y, fbp.MarginRect.width, fbp.MarginRect.height);
- return sum + fbp.Rect.width;
- }
- }
- else if (histoBox.ChartType == ChartType.HorizontalBar) {
- if (this.histoOp.X.AggregateFunction == AggregateFunction.Count) {
- fbp.Rect = new PIXIRectangle(fbp.Rect.x + sum, fbp.Rect.y, fbp.Rect.width, fbp.Rect.height);
- fbp.MarginRect = new PIXIRectangle(fbp.MarginRect.x + sum, fbp.MarginRect.y, fbp.MarginRect.width, fbp.MarginRect.height);
- return sum + fbp.Rect.width;
- }
- if (this.histoOp.X.AggregateFunction == AggregateFunction.Avg) {
- var h = fbp.Rect.height / 2.0;
- fbp.Rect = new PIXIRectangle(fbp.Rect.x, fbp.Rect.y + sum, fbp.Rect.width, fbp.Rect.height / filteredBinPrims.length);
- fbp.MarginRect = new PIXIRectangle(fbp.MarginRect.x, fbp.MarginRect.y - h + sum + (fbp.Rect.height / 2.0), fbp.MarginRect.width, fbp.MarginRect.height);
- return sum + fbp.Rect.height;
- }
- }
- return 0;
- }, 0);
- this.BinPrimitives = this.BinPrimitives.reverse();
- var f = this.BinPrimitives.filter(b => b.BrushIndex == allBrushIndex);
- this.HitGeom = f.length > 0 ? f[0].Rect : PIXIRectangle.EMPTY;
- }
- private setupBrushing(bin: Bin, normalization: number) {
- var overlapBrushIndex = ModelHelpers.OverlapBrushIndex(this.histoResult);
- var orderedBrushes = [this.histoResult.brushes![0], this.histoResult.brushes![overlapBrushIndex]];
- this.histoResult.brushes!.map(brush => brush.brushIndex != 0 && brush.brushIndex != overlapBrushIndex && orderedBrushes.push(brush));
- return {
- orderedBrushes,
- maxAxis: orderedBrushes.reduce((prev, Brush) => {
- let aggResult = this.histoOp.getValue(normalization, bin, this.histoResult, Brush.brushIndex!);
- return aggResult != undefined && aggResult > prev ? aggResult : prev;
- }, Number.MIN_VALUE)
- };
- }
- private createHeatmapBinPrimitives(bin: Bin, brush: Brush, brushFactorSum: number): number {
-
- let unNormalizedValue = this.histoOp.getValue(2, bin, this.histoResult, brush.brushIndex!);
- if (unNormalizedValue == undefined)
- return brushFactorSum;
-
- var normalizedValue = (unNormalizedValue - this._histoBox.ValueRange[0]) / (Math.abs((this._histoBox.ValueRange[1] - this._histoBox.ValueRange[0])) < HistogramBinPrimitiveCollection.TOLERANCE ?
- unNormalizedValue : this._histoBox.ValueRange[1] - this._histoBox.ValueRange[0]);
-
- let allUnNormalizedValue = this.histoOp.getValue(2, bin, this.histoResult, ModelHelpers.AllBrushIndex(this.histoResult))
-
- // bcz: are these calls needed?
- let [xFrom, xTo] = this.sizeConverter.DataToScreenXAxisRange(this._histoBox.VisualBinRanges, 0, bin);
- let [yFrom, yTo] = this.sizeConverter.DataToScreenYAxisRange(this._histoBox.VisualBinRanges, 1, bin);
-
- var returnBrushFactorSum = brushFactorSum;
- if (allUnNormalizedValue != undefined) {
- var brushFactor = (unNormalizedValue / allUnNormalizedValue);
- returnBrushFactorSum += brushFactor;
- returnBrushFactorSum = Math.min(returnBrushFactorSum, 1.0);
-
- var tempRect = new PIXIRectangle(xFrom, yTo, xTo - xFrom, yFrom - yTo);
- var ratio = (tempRect.width / tempRect.height);
- var newHeight = Math.sqrt((1.0 / ratio) * ((tempRect.width * tempRect.height) * returnBrushFactorSum));
- var newWidth = newHeight * ratio;
-
- xFrom = (tempRect.x + (tempRect.width - newWidth) / 2.0);
- yTo = (tempRect.y + (tempRect.height - newHeight) / 2.0);
- xTo = (xFrom + newWidth);
- yFrom = (yTo + newHeight);
- }
- var alpha = 0.0;
- var color = this.baseColorFromBrush(brush);
- var lerpColor = LABColor.Lerp(
- LABColor.FromColor(StyleConstants.MIN_VALUE_COLOR),
- LABColor.FromColor(color),
- (alpha + Math.pow(normalizedValue, 1.0 / 3.0) * (1.0 - alpha)));
- var dataColor = LABColor.ToColor(lerpColor);
-
- this.createBinPrimitive(-1, brush, PIXIRectangle.EMPTY, 0, xFrom, xTo, yFrom, yTo, dataColor, 1, unNormalizedValue);
- return returnBrushFactorSum;
- }
-
- private createSinglePointChartBinPrimitives(bin: Bin, brush: Brush): number {
- let unNormalizedValue = this._histoBox.HistoOp.getValue(2, bin, this.histoResult, brush.brushIndex!);
- if (unNormalizedValue != undefined) {
- let [xFrom, xTo] = this.sizeConverter.DataToScreenPointRange(0, bin, ModelHelpers.CreateAggregateKey(this.histoOp.Schema!.distinctAttributeParameters, this.histoOp.X, this.histoResult, brush.brushIndex!));
- let [yFrom, yTo] = this.sizeConverter.DataToScreenPointRange(1, bin, ModelHelpers.CreateAggregateKey(this.histoOp.Schema!.distinctAttributeParameters, this.histoOp.Y, this.histoResult, brush.brushIndex!));
-
- if (xFrom != undefined && yFrom != undefined && xTo != undefined && yTo != undefined)
- this.createBinPrimitive(-1, brush, PIXIRectangle.EMPTY, 0, xFrom, xTo, yFrom, yTo, this.baseColorFromBrush(brush), 1, unNormalizedValue);
- }
- return 0;
- }
-
- private createVerticalBarChartBinPrimitives(bin: Bin, brush: Brush, binBrushMaxAxis: number, normalization: number): number {
- let dataValue = this.histoOp.getValue(1, bin, this.histoResult, brush.brushIndex!);
- if (dataValue != undefined) {
- let [yFrom, yValue, yTo] = this.sizeConverter.DataToScreenNormalizedRange(dataValue, normalization, 1, binBrushMaxAxis);
- let [xFrom, xTo] = this.sizeConverter.DataToScreenXAxisRange(this._histoBox.VisualBinRanges, 0, bin);
-
- var yMarginAbsolute = this.getMargin(bin, brush, this.histoOp.Y);
- var marginRect = new PIXIRectangle(xFrom + (xTo - xFrom) / 2.0 - 1,
- this.sizeConverter.DataToScreenY(yValue + yMarginAbsolute), 2,
- this.sizeConverter.DataToScreenY(yValue - yMarginAbsolute) - this.sizeConverter.DataToScreenY(yValue + yMarginAbsolute));
-
- this.createBinPrimitive(1, brush, marginRect, 0, xFrom, xTo, yFrom, yTo,
- this.baseColorFromBrush(brush), normalization != 0 ? 1 : 0.6 * binBrushMaxAxis / this.sizeConverter.DataRanges[1] + 0.4, dataValue);
- }
- return 0;
- }
-
- private createHorizontalBarChartBinPrimitives(bin: Bin, brush: Brush, binBrushMaxAxis: number, normalization: number): number {
- let dataValue = this.histoOp.getValue(0, bin, this.histoResult, brush.brushIndex!);
- if (dataValue != undefined) {
- let [xFrom, xValue, xTo] = this.sizeConverter.DataToScreenNormalizedRange(dataValue, normalization, 0, binBrushMaxAxis);
- let [yFrom, yTo] = this.sizeConverter.DataToScreenYAxisRange(this._histoBox.VisualBinRanges, 1, bin);
-
- var xMarginAbsolute = this.sizeConverter.IsSmall ? 0 : this.getMargin(bin, brush, this.histoOp.X);
- var marginRect = new PIXIRectangle(this.sizeConverter.DataToScreenX(xValue - xMarginAbsolute),
- yTo + (yFrom - yTo) / 2.0 - 1,
- this.sizeConverter.DataToScreenX(xValue + xMarginAbsolute) - this.sizeConverter.DataToScreenX(xValue - xMarginAbsolute),
- 2.0);
-
- this.createBinPrimitive(0, brush, marginRect, 0, xFrom, xTo, yFrom, yTo,
- this.baseColorFromBrush(brush), normalization != 1 ? 1 : 0.6 * binBrushMaxAxis / this.sizeConverter.DataRanges[0] + 0.4, dataValue);
- }
- return 0;
- }
-
-
- private getMargin(bin: Bin, brush: Brush, axis: AttributeTransformationModel) {
- var marginParams = new MarginAggregateParameters();
- marginParams.aggregateFunction = axis.AggregateFunction;
- var marginAggregateKey = ModelHelpers.CreateAggregateKey(this.histoOp.Schema!.distinctAttributeParameters, axis, this.histoResult, brush.brushIndex!, marginParams);
- var marginResult = ModelHelpers.GetAggregateResult(bin, marginAggregateKey) as MarginAggregateResult;
- return !marginResult ? 0 : marginResult.absolutMargin!;
- }
-
- private createBinPrimitive(barAxis: number, brush: Brush, marginRect: PIXIRectangle,
- marginPercentage: number, xFrom: number, xTo: number, yFrom: number, yTo: number, color: number, opacity: number, dataValue: number) {
- var binPrimitive = new HistogramBinPrimitive(
- {
- Rect: new PIXIRectangle(xFrom, yTo, xTo - xFrom, yFrom - yTo),
- MarginRect: marginRect,
- MarginPercentage: marginPercentage,
- BrushIndex: brush.brushIndex,
- Color: color,
- Opacity: opacity,
- DataValue: dataValue,
- BarAxis: barAxis
- });
- this.BinPrimitives.push(binPrimitive);
- }
-
- private baseColorFromBrush(brush: Brush): number {
- let bc = StyleConstants.BRUSH_COLORS;
- if (brush.brushIndex == ModelHelpers.RestBrushIndex(this.histoResult)) {
- return StyleConstants.HIGHLIGHT_COLOR;
- }
- else if (brush.brushIndex == ModelHelpers.OverlapBrushIndex(this.histoResult)) {
- return StyleConstants.OVERLAP_COLOR;
- }
- else if (brush.brushIndex == ModelHelpers.AllBrushIndex(this.histoResult)) {
- return 0x00ff00;
- }
- else if (bc.length > 0) {
- return bc[brush.brushIndex! % bc.length];
- }
- // else if (this.histoOp.BrushColors.length > 0) {
- // return this.histoOp.BrushColors[brush.brushIndex! % this.histoOp.BrushColors.length];
- // }
- return StyleConstants.HIGHLIGHT_COLOR;
- }
}
\ No newline at end of file
diff --git a/src/client/northstar/dash-nodes/HistogramLabelPrimitives.tsx b/src/client/northstar/dash-nodes/HistogramLabelPrimitives.tsx
index 45b23874d..93b237deb 100644
--- a/src/client/northstar/dash-nodes/HistogramLabelPrimitives.tsx
+++ b/src/client/northstar/dash-nodes/HistogramLabelPrimitives.tsx
@@ -5,8 +5,9 @@ import { Utils as DashUtils } from '../../../Utils';
import { NominalVisualBinRange } from "../model/binRanges/NominalVisualBinRange";
import "../utils/Extensions";
import { StyleConstants } from "../utils/StyleContants";
-import { HistogramBox, HistogramPrimitivesProps } from "./HistogramBox";
+import { HistogramBox } from "./HistogramBox";
import "./HistogramLabelPrimitives.scss";
+import { HistogramPrimitivesProps } from "./HistogramBoxPrimitives";
@observer
export class HistogramLabelPrimitives extends React.Component {
diff --git a/src/client/northstar/operations/HistogramOperation.ts b/src/client/northstar/operations/HistogramOperation.ts
index 48bad73df..4689cb233 100644
--- a/src/client/northstar/operations/HistogramOperation.ts
+++ b/src/client/northstar/operations/HistogramOperation.ts
@@ -1,5 +1,7 @@
import { action, computed, observable, trace } from "mobx";
import { Document } from "../../../fields/Document";
+import { FieldWaiting } from "../../../fields/Field";
+import { KeyStore } from "../../../fields/KeyStore";
import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils";
import { ColumnAttributeModel } from "../core/attribute/AttributeModel";
import { AttributeTransformationModel } from "../core/attribute/AttributeTransformationModel";
@@ -7,52 +9,30 @@ import { CalculatedAttributeManager } from "../core/attribute/CalculatedAttribut
import { FilterModel } from "../core/filter/FilterModel";
import { FilterOperand } from "../core/filter/FilterOperand";
import { IBaseFilterConsumer } from "../core/filter/IBaseFilterConsumer";
-import { IBaseFilterProvider, instanceOfIBaseFilterProvider } from "../core/filter/IBaseFilterProvider";
+import { IBaseFilterProvider } from "../core/filter/IBaseFilterProvider";
+import { HistogramField } from "../dash-fields/HistogramField";
import { SETTINGS_SAMPLE_SIZE, SETTINGS_X_BINS, SETTINGS_Y_BINS } from "../model/binRanges/VisualBinRangeHelper";
-import { AggregateFunction, AggregateParameters, Attribute, AverageAggregateParameters, DataType, HistogramOperationParameters, QuantitativeBinRange, HistogramResult, Brush, DoubleValueAggregateResult, Bin } from "../model/idea/idea";
+import { AggregateFunction, AggregateParameters, Attribute, AverageAggregateParameters, Bin, DataType, DoubleValueAggregateResult, HistogramOperationParameters, HistogramResult, QuantitativeBinRange } from "../model/idea/idea";
import { ModelHelpers } from "../model/ModelHelpers";
import { ArrayUtil } from "../utils/ArrayUtil";
import { BaseOperation } from "./BaseOperation";
-import { KeyStore } from "../../../fields/KeyStore";
-import { HistogramField } from "../dash-fields/HistogramField";
-import { FieldWaiting } from "../../../fields/Field";
-import { StyleConstants } from "../utils/StyleContants";
-
export class HistogramOperation extends BaseOperation implements IBaseFilterConsumer, IBaseFilterProvider {
+ public static Empty = new HistogramOperation("-empty schema-", new AttributeTransformationModel(new ColumnAttributeModel(new Attribute())), new AttributeTransformationModel(new ColumnAttributeModel(new Attribute())), new AttributeTransformationModel(new ColumnAttributeModel(new Attribute())));
@observable public FilterOperand: FilterOperand = FilterOperand.AND;
@observable public Links: Document[] = [];
@observable public BrushLinks: { l: Document, b: Document }[] = [];
@observable public BrushColors: number[] = [];
- @observable public Normalization: number = -1;
@observable public FilterModels: FilterModel[] = [];
+
+ @observable public Normalization: number = -1;
@observable public X: AttributeTransformationModel;
@observable public Y: AttributeTransformationModel;
@observable public V: AttributeTransformationModel;
@observable public SchemaName: string;
+ @observable public QRange: QuantitativeBinRange | undefined;
@computed public get Schema() { return CurrentUserUtils.GetNorthstarSchema(this.SchemaName); }
- @action
- public AddFilterModels(filterModels: FilterModel[]): void {
- filterModels.filter(f => f !== null).forEach(fm => this.FilterModels.push(fm));
- }
- @action
- public RemoveFilterModels(filterModels: FilterModel[]): void {
- ArrayUtil.RemoveMany(this.FilterModels, filterModels);
- }
-
- public getValue(axis: number, bin: Bin, result: HistogramResult, brushIndex: number) {
- var aggregateKey = ModelHelpers.CreateAggregateKey(this.Schema!.distinctAttributeParameters, axis == 0 ? this.X : axis == 1 ? this.Y : this.V, result, brushIndex);
- let dataValue = ModelHelpers.GetAggregateResult(bin, aggregateKey) as DoubleValueAggregateResult;
- return dataValue != null && dataValue.hasResult ? dataValue.result : undefined;
- }
-
- public static Empty = new HistogramOperation("-empty schema-", new AttributeTransformationModel(new ColumnAttributeModel(new Attribute())), new AttributeTransformationModel(new ColumnAttributeModel(new Attribute())), new AttributeTransformationModel(new ColumnAttributeModel(new Attribute())));
-
- Equals(other: Object): boolean {
- throw new Error("Method not implemented.");
- }
-
constructor(schemaName: string, x: AttributeTransformationModel, y: AttributeTransformationModel, v: AttributeTransformationModel, normalized?: number) {
super();
this.X = x;
@@ -62,6 +42,19 @@ export class HistogramOperation extends BaseOperation implements IBaseFilterCons
this.SchemaName = schemaName;
}
+ Equals(other: Object): boolean {
+ throw new Error("Method not implemented.");
+ }
+
+ @action
+ public AddFilterModels(filterModels: FilterModel[]): void {
+ filterModels.filter(f => f !== null).forEach(fm => this.FilterModels.push(fm));
+ }
+ @action
+ public RemoveFilterModels(filterModels: FilterModel[]): void {
+ ArrayUtil.RemoveMany(this.FilterModels, filterModels);
+ }
+
@computed
public get FilterString(): string {
let filterModels: FilterModel[] = [];
@@ -73,25 +66,16 @@ export class HistogramOperation extends BaseOperation implements IBaseFilterCons
trace();
let brushes: string[] = [];
this.BrushLinks.map(brushLink => {
- let brusherDoc = brushLink.b;
- let brushHistogram = brusherDoc.GetT(KeyStore.Data, HistogramField);
+ let brushHistogram = brushLink.b.GetT(KeyStore.Data, HistogramField);
if (brushHistogram && brushHistogram != FieldWaiting) {
let filterModels: FilterModel[] = [];
- let brush = FilterModel.GetFilterModelsRecursive(brushHistogram!.Data, new Set(), filterModels, false)
- brushes.push(brush);
+ brushes.push(FilterModel.GetFilterModelsRecursive(brushHistogram.Data, new Set(), filterModels, false));
}
});
return brushes;
}
-
- @computed.struct
- public get SelectionString() {
- let filterModels = new Array();
- return FilterModel.GetFilterModelsRecursive(this, new Set(), filterModels, false);
- }
-
- GetAggregateParameters(histoX: AttributeTransformationModel, histoY: AttributeTransformationModel, histoValue: AttributeTransformationModel) {
+ private getAggregateParameters(histoX: AttributeTransformationModel, histoY: AttributeTransformationModel, histoValue: AttributeTransformationModel) {
let allAttributes = new Array(histoX, histoY, histoValue);
allAttributes = ArrayUtil.Distinct(allAttributes.filter(a => a.AggregateFunction !== AggregateFunction.None));
@@ -108,11 +92,9 @@ export class HistogramOperation extends BaseOperation implements IBaseFilterCons
return [perBinAggregateParameters, globalAggregateParameters];
}
- public QRange: QuantitativeBinRange | undefined;
-
public CreateOperationParameters(): HistogramOperationParameters | undefined {
if (this.X && this.Y && this.V) {
- let [perBinAggregateParameters, globalAggregateParameters] = this.GetAggregateParameters(this.X, this.Y, this.V);
+ let [perBinAggregateParameters, globalAggregateParameters] = this.getAggregateParameters(this.X, this.Y, this.V);
return new HistogramOperationParameters({
enableBrushComputation: true,
adapterName: this.SchemaName,
@@ -131,9 +113,6 @@ export class HistogramOperation extends BaseOperation implements IBaseFilterCons
});
}
}
- get_random_color(): number {
- return (Math.floor(Math.random() * 256) << 16) + (Math.floor(Math.random() * 256) << 8) + (Math.floor(Math.random() * 256));
- }
@action
public async Update(): Promise {
--
cgit v1.2.3-70-g09d2
From a2e4321eb23bedda9b78f012d3eb061045c5b33c Mon Sep 17 00:00:00 2001
From: Bob Zeleznik
Date: Fri, 29 Mar 2019 22:50:49 -0400
Subject: improved brushing
---
src/client/northstar/dash-nodes/HistogramBox.tsx | 5 +-
src/client/northstar/operations/BaseOperation.ts | 5 +-
.../CollectionFreeFormLinksView.tsx | 56 ++++++++++------------
3 files changed, 29 insertions(+), 37 deletions(-)
(limited to 'src/client/northstar/operations')
diff --git a/src/client/northstar/dash-nodes/HistogramBox.tsx b/src/client/northstar/dash-nodes/HistogramBox.tsx
index 6bf2697fc..65d917fd3 100644
--- a/src/client/northstar/dash-nodes/HistogramBox.tsx
+++ b/src/client/northstar/dash-nodes/HistogramBox.tsx
@@ -36,7 +36,7 @@ export class HistogramBox extends React.Component {
@observable public HistoOp: HistogramOperation = HistogramOperation.Empty;
@observable public VisualBinRanges: VisualBinRange[] = [];
@observable public ValueRange: number[] = [];
- @observable public HistogramResult: HistogramResult = new HistogramResult();
+ @computed public get HistogramResult(): HistogramResult { return this.HistoOp.Result as HistogramResult; }
@observable public SizeConverter: SizeConverter = new SizeConverter();
@computed get createOperationParamsCache() { trace(); return this.HistoOp.CreateOperationParameters(); }
@@ -120,7 +120,6 @@ export class HistogramBox extends React.Component {
this.props.doc.GetTAsync(this.props.fieldKey, HistogramField).then((histoOp: Opt) => runInAction(() => {
this.HistoOp = histoOp ? histoOp.Data : HistogramOperation.Empty;
if (this.HistoOp != HistogramOperation.Empty) {
- this.HistoOp.YieldResult = (r: Result) => action(() => this.HistogramResult = r as HistogramResult)();
reaction(() => this.props.doc.GetList(KeyStore.LinkedFromDocs, []), (docs: Document[]) => this.HistoOp.Links.splice(0, this.HistoOp.Links.length, ...docs), { fireImmediately: true });
reaction(() => this.props.doc.GetList(KeyStore.BrushingDocs, []).length,
() => {
@@ -128,7 +127,7 @@ export class HistogramBox extends React.Component {
var availableColors = StyleConstants.BRUSH_COLORS.map(c => c);
let proto = this.props.doc.GetPrototype() as Document;
let brushingLinks = brushingDocs.map((brush, i) => {
- // brush.SetNumber(KeyStore.BackgroundColor, availableColors[i % availableColors.length]);
+ brush.SetNumber(KeyStore.BackgroundColor, availableColors[i % availableColors.length]);
let brushed = brush.GetList(KeyStore.BrushingDocs, [] as Document[]);
if (!brushed || brushed.length < 2)
return undefined;
diff --git a/src/client/northstar/operations/BaseOperation.ts b/src/client/northstar/operations/BaseOperation.ts
index 21d1db749..f545b2c58 100644
--- a/src/client/northstar/operations/BaseOperation.ts
+++ b/src/client/northstar/operations/BaseOperation.ts
@@ -11,7 +11,7 @@ export abstract class BaseOperation {
@observable public Error: string = "";
@observable public OverridingFilters: FilterModel[] = [];
//@observable
- public Result?: Result = undefined;
+ @observable public Result?: Result = undefined;
@observable public ComputationStarted: boolean = false;
public OperationReference?: OperationReference = undefined;
@@ -46,11 +46,8 @@ export abstract class BaseOperation {
}
- public YieldResult: ((result: Result) => void) | undefined;
@action
public SetResult(result: Result): void {
- if (this.YieldResult)
- this.YieldResult(result);
this.Result = result;
}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
index 8dbf80533..2dcf7fbbe 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
@@ -3,17 +3,15 @@ import { observer } from "mobx-react";
import { Document } from "../../../../fields/Document";
import { FieldWaiting } from "../../../../fields/Field";
import { KeyStore } from "../../../../fields/KeyStore";
+import { ListField } from "../../../../fields/ListField";
import { Utils } from "../../../../Utils";
import { DocumentManager } from "../../../util/DocumentManager";
import { DocumentView } from "../../nodes/DocumentView";
import { CollectionViewProps } from "../CollectionViewBase";
import "./CollectionFreeFormLinksView.scss";
+import { CollectionFreeFormLinkView } from "./CollectionFreeFormLinkView";
import React = require("react");
import v5 = require("uuid/v5");
-import { CollectionFreeFormLinkView } from "./CollectionFreeFormLinkView";
-import { ListField } from "../../../../fields/ListField";
-import { TextField } from "../../../../fields/TextField";
-import { StyleConstants } from "../../../northstar/utils/StyleContants";
@observer
export class CollectionFreeFormLinksView extends React.Component {
@@ -31,36 +29,34 @@ export class CollectionFreeFormLinksView extends React.Component
- srcDoc.GetTAsync(KeyStore.Prototype, Document).then((protoSrc) => runInAction(() => {
- linkDoc.Set(KeyStore.Title, new TextField("New Brush"));
- linkDoc.Set(KeyStore.LinkDescription, new TextField(""));
- linkDoc.Set(KeyStore.LinkTags, new TextField("Default"));
- linkDoc.SetNumber(KeyStore.BackgroundColor, StyleConstants.BRUSH_COLORS[0]);
-
- let dstTarg = (protoDest ? protoDest : dstDoc);
- let srcTarg = (protoSrc ? protoSrc : srcDoc);
+ dstDoc.GetTAsync(KeyStore.Prototype, Document).then((protoDest) =>
+ srcDoc.GetTAsync(KeyStore.Prototype, Document).then((protoSrc) => runInAction(() => {
+ let dstTarg = (protoDest ? protoDest : dstDoc);
+ let srcTarg = (protoSrc ? protoSrc : srcDoc);
+ let findBrush = (field: ListField) => field.Data.findIndex(brush => {
+ let bdocs = brush.GetList(KeyStore.BrushingDocs, [] as Document[]);
+ return (bdocs[0] == dstTarg && bdocs[1] == srcTarg) || (bdocs[0] == srcTarg && bdocs[1] == dstTarg)
+ });
+ let brushAction = (field: ListField) => {
+ let found = findBrush(field);
+ if (found != -1)
+ field.Data.splice(found, 1);
+ };
+ if (Math.abs(x1 + x1w - x2) < 20 || Math.abs(x2 + x2w - x1) < 20) {
+ let linkDoc: Document = new Document();
+ linkDoc.SetText(KeyStore.Title, "Histogram Brush");
+ linkDoc.SetText(KeyStore.LinkDescription, "Brush between " + srcTarg.Title + " and " + dstTarg.Title);
linkDoc.SetData(KeyStore.BrushingDocs, [dstTarg, srcTarg], ListField);
- dstTarg.GetOrCreateAsync(KeyStore.BrushingDocs, ListField, field => { (field as ListField).Data.push(linkDoc) })
- srcTarg.GetOrCreateAsync(KeyStore.BrushingDocs, ListField, field => { (field as ListField).Data.push(linkDoc) })
- }))
- )
- } else {
- dstDoc.GetTAsync(KeyStore.Prototype, Document).then((protoDest) =>
- srcDoc.GetTAsync(KeyStore.Prototype, Document).then((protoSrc) => runInAction(() => {
- let dstTarg = (protoDest ? protoDest : dstDoc);
- let srcTarg = (protoSrc ? protoSrc : srcDoc);
- dstTarg.GetOrCreateAsync(KeyStore.BrushingDocs, ListField, field => { (field as ListField).Data.length = 0 })
- srcTarg.GetOrCreateAsync(KeyStore.BrushingDocs, ListField, field => { (field as ListField).Data.length = 0 })
- }))
- )
- }
+ brushAction = (field: ListField) => (findBrush(field) == -1) && field.Data.push(linkDoc);
+ }
+ dstTarg.GetOrCreateAsync(KeyStore.BrushingDocs, ListField, brushAction);
+ srcTarg.GetOrCreateAsync(KeyStore.BrushingDocs, ListField, brushAction);
+ }
+ )))
}
}
- });
+ })
}
documentAnchors(view: DocumentView) {
let equalViews = [view];
--
cgit v1.2.3-70-g09d2
From 74e95e596d9876e90c294ade30df3d666d167139 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik
Date: Fri, 29 Mar 2019 23:48:34 -0400
Subject: fixed brush colors.
---
src/client/northstar/dash-fields/HistogramField.ts | 2 +-
src/client/northstar/dash-nodes/HistogramBox.tsx | 10 +++-------
src/client/northstar/operations/HistogramOperation.ts | 2 +-
.../collectionFreeForm/CollectionFreeFormLinksView.tsx | 10 ++++++----
4 files changed, 11 insertions(+), 13 deletions(-)
(limited to 'src/client/northstar/operations')
diff --git a/src/client/northstar/dash-fields/HistogramField.ts b/src/client/northstar/dash-fields/HistogramField.ts
index ae83ea5ba..4a557e123 100644
--- a/src/client/northstar/dash-fields/HistogramField.ts
+++ b/src/client/northstar/dash-fields/HistogramField.ts
@@ -25,7 +25,7 @@ export class HistogramField extends BasicField {
return dup;
}
toString(): string {
- return JSON.stringify(this.omitKeys(this.Data, ['Links', 'BrushLinks', 'Result']));
+ return JSON.stringify(this.omitKeys(this.Data, ['Links', 'BrushLinks', 'Result', 'BrushColors']));
}
Copy(): Field {
diff --git a/src/client/northstar/dash-nodes/HistogramBox.tsx b/src/client/northstar/dash-nodes/HistogramBox.tsx
index 65d917fd3..a968def96 100644
--- a/src/client/northstar/dash-nodes/HistogramBox.tsx
+++ b/src/client/northstar/dash-nodes/HistogramBox.tsx
@@ -124,16 +124,12 @@ export class HistogramBox extends React.Component {
reaction(() => this.props.doc.GetList(KeyStore.BrushingDocs, []).length,
() => {
let brushingDocs = this.props.doc.GetList(KeyStore.BrushingDocs, [] as Document[]);
- var availableColors = StyleConstants.BRUSH_COLORS.map(c => c);
let proto = this.props.doc.GetPrototype() as Document;
- let brushingLinks = brushingDocs.map((brush, i) => {
- brush.SetNumber(KeyStore.BackgroundColor, availableColors[i % availableColors.length]);
+ this.HistoOp.BrushLinks.splice(0, this.HistoOp.BrushLinks.length, ...brushingDocs.map((brush, i) => {
+ brush.SetNumber(KeyStore.BackgroundColor, StyleConstants.BRUSH_COLORS[i % StyleConstants.BRUSH_COLORS.length]);
let brushed = brush.GetList(KeyStore.BrushingDocs, [] as Document[]);
- if (!brushed || brushed.length < 2)
- return undefined;
return { l: brush, b: brushed[0].Id == proto.Id ? brushed[1] : brushed[0] }
- }).filter(x => x != undefined) as { l: Document, b: Document }[];
- this.HistoOp.BrushLinks.splice(0, this.HistoOp.BrushLinks.length, ...brushingLinks);
+ }));
}, { fireImmediately: true });
reaction(() => this.createOperationParamsCache, () => this.HistoOp.Update(), { fireImmediately: true });
}
diff --git a/src/client/northstar/operations/HistogramOperation.ts b/src/client/northstar/operations/HistogramOperation.ts
index 4689cb233..e63de1632 100644
--- a/src/client/northstar/operations/HistogramOperation.ts
+++ b/src/client/northstar/operations/HistogramOperation.ts
@@ -116,7 +116,7 @@ export class HistogramOperation extends BaseOperation implements IBaseFilterCons
@action
public async Update(): Promise {
- //this.BrushColors = this.BrushLinks.map(e => e.l.GetNumber(KeyStore.BackgroundColor, 0));
+ this.BrushColors = this.BrushLinks.map(e => e.l.GetNumber(KeyStore.BackgroundColor, 0));
return super.Update();
}
}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
index 2dcf7fbbe..f793b3a49 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
@@ -26,16 +26,18 @@ export class CollectionFreeFormLinksView extends React.Component
srcDoc.GetTAsync(KeyStore.Prototype, Document).then((protoSrc) => runInAction(() => {
let dstTarg = (protoDest ? protoDest : dstDoc);
let srcTarg = (protoSrc ? protoSrc : srcDoc);
let findBrush = (field: ListField) => field.Data.findIndex(brush => {
let bdocs = brush.GetList(KeyStore.BrushingDocs, [] as Document[]);
- return (bdocs[0] == dstTarg && bdocs[1] == srcTarg) || (bdocs[0] == srcTarg && bdocs[1] == dstTarg)
+ return (bdocs.length == 0 || (bdocs[0] == dstTarg && bdocs[1] == srcTarg) || (bdocs[0] == srcTarg && bdocs[1] == dstTarg))
});
let brushAction = (field: ListField) => {
let found = findBrush(field);
@@ -48,7 +50,7 @@ export class CollectionFreeFormLinksView extends React.Component) => (findBrush(field) == -1) && field.Data.push(linkDoc);
+ brushAction = brushAction = (field: ListField) => (findBrush(field) == -1) && field.Data.push(linkDoc);
}
dstTarg.GetOrCreateAsync(KeyStore.BrushingDocs, ListField, brushAction);
srcTarg.GetOrCreateAsync(KeyStore.BrushingDocs, ListField, brushAction);
--
cgit v1.2.3-70-g09d2