aboutsummaryrefslogtreecommitdiff
path: root/src/client/northstar/model
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/northstar/model')
-rw-r--r--src/client/northstar/model/ModelExtensions.ts48
-rw-r--r--src/client/northstar/model/ModelHelpers.ts215
-rw-r--r--src/client/northstar/model/binRanges/AlphabeticVisualBinRange.ts52
-rw-r--r--src/client/northstar/model/binRanges/DateTimeVisualBinRange.ts105
-rw-r--r--src/client/northstar/model/binRanges/NominalVisualBinRange.ts52
-rw-r--r--src/client/northstar/model/binRanges/QuantitativeVisualBinRange.ts90
-rw-r--r--src/client/northstar/model/binRanges/VisualBinRange.ts36
-rw-r--r--src/client/northstar/model/binRanges/VisualBinRangeHelper.ts71
8 files changed, 669 insertions, 0 deletions
diff --git a/src/client/northstar/model/ModelExtensions.ts b/src/client/northstar/model/ModelExtensions.ts
new file mode 100644
index 000000000..9fcba7f1c
--- /dev/null
+++ b/src/client/northstar/model/ModelExtensions.ts
@@ -0,0 +1,48 @@
+import { AttributeParameters, Brush, MarginAggregateParameters, SingleDimensionAggregateParameters, Solution } from '../model/idea/idea'
+import { Utils } from '../utils/Utils'
+
+import { FilterModel } from '../core/filter/FilterModel'
+
+(SingleDimensionAggregateParameters as any).prototype["Equals"] = function (other: Object) {
+ if (!Utils.EqualityHelper(this, other)) return false;
+ if (!Utils.EqualityHelper((this as SingleDimensionAggregateParameters).attributeParameters!,
+ (other as SingleDimensionAggregateParameters).attributeParameters!)) return false;
+ if (!((this as SingleDimensionAggregateParameters).attributeParameters! as any)["Equals"]((other as SingleDimensionAggregateParameters).attributeParameters)) return false;
+ return true;
+}
+
+{
+ (AttributeParameters as any).prototype["Equals"] = function (other: AttributeParameters) {
+ return (<any>this).constructor.name === (<any>other).constructor.name &&
+ this.rawName === other.rawName;
+ }
+}
+
+{
+ (Solution as any).prototype["Equals"] = function (other: Object) {
+ if (!Utils.EqualityHelper(this, other)) return false;
+ if ((this as Solution).solutionId !== (other as Solution).solutionId) return false;
+ return true;
+ }
+}
+
+{
+ (MarginAggregateParameters as any).prototype["Equals"] = function (other: Object) {
+ if (!Utils.EqualityHelper(this, other)) return false;
+ if (!Utils.EqualityHelper((this as SingleDimensionAggregateParameters).attributeParameters!,
+ (other as SingleDimensionAggregateParameters).attributeParameters!)) return false;
+ if (!((this as SingleDimensionAggregateParameters).attributeParameters! as any)["Equals"]((other as SingleDimensionAggregateParameters).attributeParameters!)) return false;
+
+ if ((this as MarginAggregateParameters).aggregateFunction !== (other as MarginAggregateParameters).aggregateFunction) return false;
+ return true;
+ }
+}
+
+{
+ (Brush as any).prototype["Equals"] = function (other: Object) {
+ if (!Utils.EqualityHelper(this, other)) return false;
+ if ((this as Brush).brushEnum !== (other as Brush).brushEnum) return false;
+ if ((this as Brush).brushIndex !== (other as Brush).brushIndex) return false;
+ return true;
+ }
+} \ No newline at end of file
diff --git a/src/client/northstar/model/ModelHelpers.ts b/src/client/northstar/model/ModelHelpers.ts
new file mode 100644
index 000000000..e1241b3ef
--- /dev/null
+++ b/src/client/northstar/model/ModelHelpers.ts
@@ -0,0 +1,215 @@
+
+import { action } from "mobx";
+import { AggregateFunction, AggregateKey, AggregateParameters, AttributeColumnParameters, AttributeParameters, AverageAggregateParameters, Bin, BinningParameters, Brush, BrushEnum, CountAggregateParameters, DataType, EquiWidthBinningParameters, HistogramResult, MarginAggregateParameters, SingleBinBinningParameters, SingleDimensionAggregateParameters, SumAggregateParameters, AggregateBinRange, NominalBinRange, AlphabeticBinRange, Predicate, Schema, Attribute, AttributeGroup, Exception, AttributeBackendParameters, AttributeCodeParameters } from '../model/idea/idea';
+import { ValueComparison } from "../core/filter/ValueComparision";
+import { ArrayUtil } from "../utils/ArrayUtil";
+import { AttributeModel, ColumnAttributeModel, BackendAttributeModel, CodeAttributeModel } from "../core/attribute/AttributeModel";
+import { FilterModel } from "../core/filter/FilterModel";
+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";
+
+export class ModelHelpers {
+
+ public static CreateAggregateKey(atm: AttributeTransformationModel, histogramResult: HistogramResult,
+ brushIndex: number, aggParameters?: SingleDimensionAggregateParameters): AggregateKey {
+ {
+ if (aggParameters == undefined) {
+ aggParameters = ModelHelpers.GetAggregateParameter(atm);
+ }
+ else {
+ aggParameters.attributeParameters = ModelHelpers.GetAttributeParameters(atm.AttributeModel);
+ }
+ return new AggregateKey(
+ {
+ aggregateParameterIndex: ModelHelpers.GetAggregateParametersIndex(histogramResult, aggParameters),
+ brushIndex: brushIndex
+ });
+ }
+ }
+
+ public static GetAggregateParametersIndex(histogramResult: HistogramResult, aggParameters?: AggregateParameters): number {
+ return ArrayUtil.IndexOfWithEqual(histogramResult.aggregateParameters!, aggParameters);
+ }
+
+ public static GetAggregateParameter(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 = Main.Instance.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;
+ aggParam = cnt;
+ }
+ else if (atm.AggregateFunction === AggregateFunction.Sum) {
+ var sum = new SumAggregateParameters();
+ sum.attributeParameters = ModelHelpers.GetAttributeParameters(atm.AttributeModel);
+ sum.distinctAttributeParameters = Main.Instance.ActiveSchema!.distinctAttributeParameters;
+ aggParam = sum;
+ }
+ return aggParam;
+ }
+
+ public static GetAggregateParametersWithMargins(atms: Array<AttributeTransformationModel>): Array<AggregateParameters> {
+ var aggregateParameters = new Array<AggregateParameters>();
+ atms.forEach(agg => {
+ var aggParams = ModelHelpers.GetAggregateParameter(agg);
+ if (aggParams) {
+ aggregateParameters.push(aggParams);
+
+ var margin = new MarginAggregateParameters();
+ margin.attributeParameters = ModelHelpers.GetAttributeParameters(agg.AttributeModel);
+ margin.distinctAttributeParameters = Main.Instance.ActiveSchema!.distinctAttributeParameters;
+ margin.aggregateFunction = agg.AggregateFunction;
+ aggregateParameters.push(margin);
+ }
+ });
+
+ return aggregateParameters;
+ }
+
+ public static GetBinningParameters(attr: AttributeTransformationModel, nrOfBins: number, minvalue?: number, maxvalue?: number): BinningParameters {
+ if (attr.AggregateFunction === AggregateFunction.None) {
+ return new EquiWidthBinningParameters(
+ {
+ attributeParameters: ModelHelpers.GetAttributeParameters(attr.AttributeModel),
+ requestedNrOfBins: nrOfBins,
+ minValue: minvalue,
+ maxValue: maxvalue
+ });
+ }
+ else {
+ return new SingleBinBinningParameters(
+ {
+ attributeParameters: ModelHelpers.GetAttributeParameters(attr.AttributeModel)
+ });
+ }
+ }
+
+ public static GetAttributeParametersFromAttributeModel(am: AttributeModel): AttributeParameters {
+ if (am instanceof ColumnAttributeModel) {
+ return new AttributeColumnParameters(
+ {
+ rawName: am.CodeName,
+ visualizationHints: am.VisualizationHints
+ });
+ }
+ else if (am instanceof BackendAttributeModel) {
+ return new AttributeBackendParameters(
+ {
+ rawName: am.CodeName,
+ visualizationHints: am.VisualizationHints,
+ id: (am as BackendAttributeModel).Id
+ });
+ }
+ else if (am instanceof CodeAttributeModel) {
+ return new AttributeCodeParameters(
+ {
+ rawName: am.CodeName,
+ visualizationHints: am.VisualizationHints,
+ code: (am as CodeAttributeModel).Code
+ });
+ }
+ else {
+ throw new Exception()
+ }
+ }
+
+ public static GetAttributeParameters(am: AttributeModel): AttributeParameters {
+ return this.GetAttributeParametersFromAttributeModel(am);
+ }
+
+ public static OverlapBrushIndex(histogramResult: HistogramResult): number {
+ var brush = ArrayUtil.First(histogramResult.brushes!, (b: any) => b.brushEnum === BrushEnum.Overlap);
+ return ModelHelpers.GetBrushIndex(histogramResult, brush);
+ }
+
+ public static AllBrushIndex(histogramResult: HistogramResult): number {
+ var brush = ArrayUtil.First(histogramResult.brushes!, (b: any) => b.brushEnum === BrushEnum.All);
+ return ModelHelpers.GetBrushIndex(histogramResult, brush);
+ }
+
+ public static RestBrushIndex(histogramResult: HistogramResult): number {
+ var brush = ArrayUtil.First(histogramResult.brushes!, (b: Brush) => b.brushEnum === BrushEnum.Rest);
+ return ModelHelpers.GetBrushIndex(histogramResult, brush);
+ }
+
+ public static GetBrushIndex(histogramResult: HistogramResult, brush: Brush): number {
+ return ArrayUtil.IndexOfWithEqual(histogramResult.brushes!, brush);
+ }
+
+ public static GetAggregateResult(bin: Bin, aggregateKey: AggregateKey) {
+ if (aggregateKey.aggregateParameterIndex == -1 || aggregateKey.brushIndex == -1) {
+ return null;
+ }
+ return bin.aggregateResults![aggregateKey.aggregateParameterIndex! * bin.ySize! + aggregateKey.brushIndex!];
+ }
+
+ @action
+ public static PossibleAggegationFunctions(atm: AttributeTransformationModel): Array<AggregateFunction> {
+ var ret = new Array<AggregateFunction>();
+ ret.push(AggregateFunction.None);
+ ret.push(AggregateFunction.Count);
+ if (atm.AttributeModel.DataType == DataType.Float ||
+ atm.AttributeModel.DataType == DataType.Double ||
+ atm.AttributeModel.DataType == DataType.Int) {
+ ret.push(AggregateFunction.Avg);
+ ret.push(AggregateFunction.Sum);
+ }
+ return ret;
+ }
+
+ public static GetBinFilterModel(
+ bin: Bin, brushIndex: number, histogramResult: HistogramResult,
+ xAom: AttributeTransformationModel, yAom: AttributeTransformationModel): FilterModel {
+ var dimensions: Array<AttributeTransformationModel> = [xAom, yAom];
+ var filterModel = new FilterModel();
+
+ for (var i = 0; i < histogramResult.binRanges!.length; i++) {
+ if (!(histogramResult.binRanges![i] instanceof AggregateBinRange)) {
+ var binRange = VisualBinRangeHelper.GetNonAggregateVisualBinRange(histogramResult.binRanges![i]);
+ var dataFrom = binRange.GetValueFromIndex(bin.binIndex!.indices![i]);
+ var dataTo = binRange.AddStep(dataFrom);
+
+ if (binRange instanceof NominalVisualBinRange) {
+ var tt = binRange.GetLabel(dataFrom);
+ filterModel.ValueComparisons.push(new ValueComparison(dimensions[i].AttributeModel, Predicate.EQUALS, tt));
+ }
+ else if (binRange instanceof AlphabeticVisualBinRange) {
+ filterModel.ValueComparisons.push(new ValueComparison(dimensions[i].AttributeModel, Predicate.STARTS_WITH,
+ binRange.GetLabel(dataFrom)));
+ }
+ else {
+ filterModel.ValueComparisons.push(new ValueComparison(dimensions[i].AttributeModel, Predicate.GREATER_THAN_EQUAL, dataFrom));
+ filterModel.ValueComparisons.push(new ValueComparison(dimensions[i].AttributeModel, Predicate.LESS_THAN, dataTo));
+ }
+ }
+ }
+
+ return filterModel;
+ }
+
+ public GetAllAttributes(schema: Schema) {
+ if (!schema || !schema.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<Attribute>();
+ recurs(allAttributes, schema.rootAttributeGroup);
+ return allAttributes;
+ }
+} \ No newline at end of file
diff --git a/src/client/northstar/model/binRanges/AlphabeticVisualBinRange.ts b/src/client/northstar/model/binRanges/AlphabeticVisualBinRange.ts
new file mode 100644
index 000000000..995bf4e0b
--- /dev/null
+++ b/src/client/northstar/model/binRanges/AlphabeticVisualBinRange.ts
@@ -0,0 +1,52 @@
+import { AlphabeticBinRange, BinLabel } from '../../model/idea/idea'
+import { VisualBinRange } from './VisualBinRange'
+
+export class AlphabeticVisualBinRange extends VisualBinRange {
+ public DataBinRange: AlphabeticBinRange;
+
+ constructor(dataBinRange: AlphabeticBinRange) {
+ super();
+ this.DataBinRange = dataBinRange;
+ }
+
+ public AddStep(value: number): number {
+ return value + 1;
+ }
+
+ public GetValueFromIndex(index: number): number {
+ return index;
+ }
+
+ public GetBins(): number[] {
+ var bins = new Array<number>();
+ var idx = 0;
+ for (var key in this.DataBinRange.labelsValue) {
+ if (this.DataBinRange.labelsValue.hasOwnProperty(key)) {
+ bins.push(idx);
+ idx++;
+ }
+ }
+ return bins;
+ }
+
+ public GetLabel(value: number): string {
+ return this.DataBinRange.prefix + this.DataBinRange.valuesLabel![value];
+ }
+
+ public GetLabels(): Array<BinLabel> {
+ var labels = new Array<BinLabel>();
+ var count = 0;
+ for (var key in this.DataBinRange.valuesLabel) {
+ if (this.DataBinRange.valuesLabel.hasOwnProperty(key)) {
+ var value = this.DataBinRange.valuesLabel[key];
+ labels.push(new BinLabel({
+ value: parseFloat(key),
+ minValue: count++,
+ maxValue: count,
+ label: this.DataBinRange.prefix + value
+ }));
+ }
+ }
+ return labels;
+ }
+} \ No newline at end of file
diff --git a/src/client/northstar/model/binRanges/DateTimeVisualBinRange.ts b/src/client/northstar/model/binRanges/DateTimeVisualBinRange.ts
new file mode 100644
index 000000000..9313fb1a7
--- /dev/null
+++ b/src/client/northstar/model/binRanges/DateTimeVisualBinRange.ts
@@ -0,0 +1,105 @@
+import { DateTimeBinRange, DateTimeStep, DateTimeStepGranularity } from '../idea/idea'
+import { VisualBinRange } from './VisualBinRange'
+
+export class DateTimeVisualBinRange extends VisualBinRange {
+ public DataBinRange: DateTimeBinRange;
+
+ constructor(dataBinRange: DateTimeBinRange) {
+ super();
+ this.DataBinRange = dataBinRange;
+ }
+
+ public AddStep(value: number): number {
+ return DateTimeVisualBinRange.AddToDateTimeTicks(value, this.DataBinRange.step!);
+ }
+
+ public GetValueFromIndex(index: number): number {
+ var v = this.DataBinRange.minValue!;
+ for (var i = 0; i < index; i++) {
+ v = this.AddStep(v);
+ }
+ return v;
+ }
+
+ public GetBins(): number[] {
+ var bins = new Array<number>();
+ for (var v: number = this.DataBinRange.minValue!;
+ v < this.DataBinRange.maxValue!;
+ v = DateTimeVisualBinRange.AddToDateTimeTicks(v, this.DataBinRange.step!)) {
+ bins.push(v);
+ }
+ return bins;
+ }
+
+ private pad(n: number, size: number) {
+ var sign = n < 0 ? '-' : '';
+ return sign + new Array(size).concat([Math.abs(n)]).join('0').slice(-size);
+ }
+
+
+ public GetLabel(value: number): string {
+ var dt = DateTimeVisualBinRange.TicksToDate(value);
+ if (this.DataBinRange.step!.dateTimeStepGranularity == DateTimeStepGranularity.Second ||
+ this.DataBinRange.step!.dateTimeStepGranularity == DateTimeStepGranularity.Minute) {
+ return ("" + this.pad(dt.getMinutes(), 2) + ":" + this.pad(dt.getSeconds(), 2));
+ //return dt.ToString("mm:ss");
+ }
+ else if (this.DataBinRange.step!.dateTimeStepGranularity == DateTimeStepGranularity.Hour) {
+ return (this.pad(dt.getHours(), 2) + ":" + this.pad(dt.getMinutes(), 2));
+ //return dt.ToString("HH:mm");
+ }
+ else if (this.DataBinRange.step!.dateTimeStepGranularity == DateTimeStepGranularity.Day) {
+ return ((dt.getMonth() + 1) + "/" + dt.getDate() + "/" + dt.getFullYear());
+ //return dt.ToString("MM/dd/yyyy");
+ }
+ else if (this.DataBinRange.step!.dateTimeStepGranularity == DateTimeStepGranularity.Month) {
+ //return dt.ToString("MM/yyyy");
+ return ((dt.getMonth() + 1) + "/" + dt.getFullYear());
+ }
+ else if (this.DataBinRange.step!.dateTimeStepGranularity == DateTimeStepGranularity.Year) {
+ return "" + dt.getFullYear();
+ }
+ return "n/a";
+ }
+
+ public static TicksToDate(ticks: number): Date {
+ var dd = new Date((ticks - 621355968000000000) / 10000);
+ dd.setMinutes(dd.getMinutes() + dd.getTimezoneOffset());
+ return dd;
+ }
+
+
+ public static DateToTicks(date: Date): number {
+ var copiedDate = new Date(date.getTime());
+ copiedDate.setMinutes(copiedDate.getMinutes() - copiedDate.getTimezoneOffset());
+ var t = copiedDate.getTime() * 10000 + 621355968000000000;
+ /*var dd = new Date((ticks - 621355968000000000) / 10000);
+ dd.setMinutes(dd.getMinutes() + dd.getTimezoneOffset());
+ return dd;*/
+ return t;
+ }
+
+ public static AddToDateTimeTicks(ticks: number, dateTimeStep: DateTimeStep): number {
+ var copiedDate = DateTimeVisualBinRange.TicksToDate(ticks);
+ var returnDate: Date = new Date(Date.now());
+ if (dateTimeStep.dateTimeStepGranularity == DateTimeStepGranularity.Second) {
+ returnDate = new Date(copiedDate.setSeconds(copiedDate.getSeconds() + dateTimeStep.dateTimeStepValue!));
+ }
+ else if (dateTimeStep.dateTimeStepGranularity == DateTimeStepGranularity.Minute) {
+ returnDate = new Date(copiedDate.setMinutes(copiedDate.getMinutes() + dateTimeStep.dateTimeStepValue!));
+ }
+ else if (dateTimeStep.dateTimeStepGranularity == DateTimeStepGranularity.Hour) {
+ returnDate = new Date(copiedDate.setHours(copiedDate.getHours() + dateTimeStep.dateTimeStepValue!));
+ }
+ else if (dateTimeStep.dateTimeStepGranularity == DateTimeStepGranularity.Day) {
+ returnDate = new Date(copiedDate.setDate(copiedDate.getDate() + dateTimeStep.dateTimeStepValue!));
+ }
+ else if (dateTimeStep.dateTimeStepGranularity == DateTimeStepGranularity.Month) {
+ returnDate = new Date(copiedDate.setMonth(copiedDate.getMonth() + dateTimeStep.dateTimeStepValue!));
+ }
+ else if (dateTimeStep.dateTimeStepGranularity == DateTimeStepGranularity.Year) {
+ returnDate = new Date(copiedDate.setFullYear(copiedDate.getFullYear() + dateTimeStep.dateTimeStepValue!));
+ }
+ return DateTimeVisualBinRange.DateToTicks(returnDate);
+ }
+} \ No newline at end of file
diff --git a/src/client/northstar/model/binRanges/NominalVisualBinRange.ts b/src/client/northstar/model/binRanges/NominalVisualBinRange.ts
new file mode 100644
index 000000000..407ff3ea6
--- /dev/null
+++ b/src/client/northstar/model/binRanges/NominalVisualBinRange.ts
@@ -0,0 +1,52 @@
+import { NominalBinRange, BinLabel } from '../../model/idea/idea'
+import { VisualBinRange } from './VisualBinRange'
+
+export class NominalVisualBinRange extends VisualBinRange {
+ public DataBinRange: NominalBinRange;
+
+ constructor(dataBinRange: NominalBinRange) {
+ super();
+ this.DataBinRange = dataBinRange;
+ }
+
+ public AddStep(value: number): number {
+ return value + 1;
+ }
+
+ public GetValueFromIndex(index: number): number {
+ return index;
+ }
+
+ public GetBins(): number[] {
+ var bins = new Array<number>();
+ var idx = 0;
+ for (var key in this.DataBinRange.labelsValue) {
+ if (this.DataBinRange.labelsValue.hasOwnProperty(key)) {
+ bins.push(idx);
+ idx++;
+ }
+ }
+ return bins;
+ }
+
+ public GetLabel(value: number): string {
+ return this.DataBinRange.valuesLabel![value];
+ }
+
+ public GetLabels(): Array<BinLabel> {
+ var labels = new Array<BinLabel>();
+ var count = 0;
+ for (var key in this.DataBinRange.valuesLabel) {
+ if (this.DataBinRange.valuesLabel.hasOwnProperty(key)) {
+ var value = this.DataBinRange.valuesLabel[key];
+ labels.push(new BinLabel({
+ value: parseFloat(key),
+ minValue: count++,
+ maxValue: count,
+ label: value
+ }));
+ }
+ }
+ return labels;
+ }
+} \ No newline at end of file
diff --git a/src/client/northstar/model/binRanges/QuantitativeVisualBinRange.ts b/src/client/northstar/model/binRanges/QuantitativeVisualBinRange.ts
new file mode 100644
index 000000000..80886416b
--- /dev/null
+++ b/src/client/northstar/model/binRanges/QuantitativeVisualBinRange.ts
@@ -0,0 +1,90 @@
+import { QuantitativeBinRange } from '../idea/idea'
+import { VisualBinRange } from './VisualBinRange';
+import { format } from "d3-format";
+
+export class QuantitativeVisualBinRange extends VisualBinRange {
+
+ public DataBinRange: QuantitativeBinRange;
+
+ constructor(dataBinRange: QuantitativeBinRange) {
+ super();
+ this.DataBinRange = dataBinRange;
+ }
+
+ public AddStep(value: number): number {
+ return value + this.DataBinRange.step!;
+ }
+
+ public GetValueFromIndex(index: number): number {
+ return this.DataBinRange.minValue! + (index * this.DataBinRange.step!);
+ }
+
+ public GetLabel(value: number): string {
+ return QuantitativeVisualBinRange.NumberFormatter(value);
+ }
+
+ public static NumberFormatter(val: number): string {
+ if (val === 0) {
+ return "0";
+ }
+ if (val < 1) {
+ /*if (val < Math.abs(0.001)) {
+ return val.toExponential(2);
+ }*/
+ return format(".3")(val);
+ }
+ return format("~s")(val);
+ }
+
+ public GetBins(): number[] {
+ let bins = new Array<number>();
+
+ for (let v: number = this.DataBinRange.minValue!; v < this.DataBinRange.maxValue!; v += this.DataBinRange.step!) {
+ bins.push(v);
+ }
+ return bins;
+ }
+
+ public static Initialize(dataMinValue: number, dataMaxValue: number, targetBinNumber: number, isIntegerRange: boolean): QuantitativeVisualBinRange {
+ let extent = QuantitativeVisualBinRange.getExtent(dataMinValue, dataMaxValue, targetBinNumber, isIntegerRange);
+ let dataBinRange = new QuantitativeBinRange();
+ dataBinRange.minValue = extent[0];
+ dataBinRange.maxValue = extent[1];
+ dataBinRange.step = extent[2];
+
+ return new QuantitativeVisualBinRange(dataBinRange);
+ }
+
+ private static getExtent(dataMin: number, dataMax: number, m: number, isIntegerRange: boolean): number[] {
+ if (dataMin === dataMax) {
+ // dataMin -= 0.1;
+ dataMax += 0.1;
+ }
+ let span = dataMax - dataMin;
+
+ let step = Math.pow(10, Math.floor(Math.log10(span / m)));
+ let err = m / span * step;
+
+ if (err <= .15) {
+ step *= 10;
+ }
+ else if (err <= .35) {
+ step *= 5;
+ }
+ else if (err <= .75) {
+ step *= 2;
+ }
+
+ if (isIntegerRange) {
+ step = Math.ceil(step);
+ }
+ let ret: number[] = new Array<number>(3);
+ let minDivStep = Math.floor(dataMin / step);
+ let maxDivStep = Math.floor(dataMax / step);
+ ret[0] = minDivStep * step; // Math.floor(Math.Round(dataMin, 8)/step)*step;
+ ret[1] = maxDivStep * step + step; // Math.floor(Math.Round(dataMax, 8)/step)*step + step;
+ ret[2] = step;
+
+ return ret;
+ }
+} \ No newline at end of file
diff --git a/src/client/northstar/model/binRanges/VisualBinRange.ts b/src/client/northstar/model/binRanges/VisualBinRange.ts
new file mode 100644
index 000000000..f53008f9a
--- /dev/null
+++ b/src/client/northstar/model/binRanges/VisualBinRange.ts
@@ -0,0 +1,36 @@
+import { BinLabel } from '../../model/idea/idea'
+
+export abstract class VisualBinRange {
+
+ constructor() {
+
+ }
+
+ public abstract AddStep(value: number): number;
+
+ public abstract GetValueFromIndex(index: number): number;
+
+ public abstract GetBins(): Array<number>;
+
+ public GetLabel(value: number): string {
+ return value.toString();
+ }
+
+ public GetLabels(): Array<BinLabel> {
+ var labels = new Array<BinLabel>();
+ var bins = this.GetBins();
+ bins.forEach(b => {
+ labels.push(new BinLabel({
+ value: b,
+ minValue: b,
+ maxValue: this.AddStep(b),
+ label: this.GetLabel(b)
+ }));
+ });
+ return labels;
+ }
+}
+
+export enum ChartType {
+ HorizontalBar = 0, VerticalBar = 1, HeatMap = 2, SinglePoint = 3
+} \ No newline at end of file
diff --git a/src/client/northstar/model/binRanges/VisualBinRangeHelper.ts b/src/client/northstar/model/binRanges/VisualBinRangeHelper.ts
new file mode 100644
index 000000000..9eae39800
--- /dev/null
+++ b/src/client/northstar/model/binRanges/VisualBinRangeHelper.ts
@@ -0,0 +1,71 @@
+import { BinRange, NominalBinRange, QuantitativeBinRange, Exception, AlphabeticBinRange, DateTimeBinRange, AggregateBinRange, DoubleValueAggregateResult, HistogramResult } from "../idea/idea";
+import { VisualBinRange, ChartType } from "./VisualBinRange";
+import { NominalVisualBinRange } from "./NominalVisualBinRange";
+import { QuantitativeVisualBinRange } from "./QuantitativeVisualBinRange";
+import { AlphabeticVisualBinRange } from "./AlphabeticVisualBinRange";
+import { DateTimeVisualBinRange } from "./DateTimeVisualBinRange";
+import { Settings } from "../../manager/Gateway";
+import { ModelHelpers } from "../ModelHelpers";
+import { AttributeTransformationModel } from "../../core/attribute/AttributeTransformationModel";
+
+export const SETTINGS_X_BINS = 15;
+export const SETTINGS_Y_BINS = 15;
+export const SETTINGS_SAMPLE_SIZE = 100000;
+
+export class VisualBinRangeHelper {
+
+ public static GetNonAggregateVisualBinRange(dataBinRange: BinRange): VisualBinRange {
+ if (dataBinRange instanceof NominalBinRange) {
+ return new NominalVisualBinRange(dataBinRange as NominalBinRange);
+ }
+ else if (dataBinRange instanceof QuantitativeBinRange) {
+ return new QuantitativeVisualBinRange(dataBinRange as QuantitativeBinRange);
+ }
+ else if (dataBinRange instanceof AlphabeticBinRange) {
+ return new AlphabeticVisualBinRange(dataBinRange as AlphabeticBinRange);
+ }
+ else if (dataBinRange instanceof DateTimeBinRange) {
+ return new DateTimeVisualBinRange(dataBinRange as DateTimeBinRange);
+ }
+ throw new Exception()
+ }
+
+ public static GetVisualBinRange(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 minValue = Number.MAX_VALUE;
+ var maxValue = Number.MIN_VALUE;
+ for (var b = 0; b < histoResult.brushes!.length; b++) {
+ var brush = histoResult.brushes![b];
+ aggregateKey.brushIndex = brush.brushIndex;
+ for (var key in histoResult.bins) {
+ if (histoResult.bins.hasOwnProperty(key)) {
+ var bin = histoResult.bins[key];
+ var res = <DoubleValueAggregateResult>ModelHelpers.GetAggregateResult(bin, aggregateKey);
+ if (res && res.hasResult && res.result) {
+ minValue = Math.min(minValue, res.result);
+ maxValue = Math.max(maxValue, res.result);
+ }
+ }
+ }
+ };
+
+ let visualBinRange = QuantitativeVisualBinRange.Initialize(minValue, maxValue, 10, false);
+
+ if (chartType == ChartType.HorizontalBar || chartType == ChartType.VerticalBar) {
+ visualBinRange = QuantitativeVisualBinRange.Initialize(Math.min(0, minValue),
+ Math.max(0, (visualBinRange as QuantitativeVisualBinRange).DataBinRange.maxValue!),
+ SETTINGS_X_BINS, false);
+ }
+ else if (chartType == ChartType.SinglePoint) {
+ visualBinRange = QuantitativeVisualBinRange.Initialize(Math.min(0, minValue), Math.max(0, maxValue),
+ SETTINGS_X_BINS, false);
+ }
+ return visualBinRange;
+ }
+ }
+}