From 5e416c352ebfb875482f890c6362fee5f84af1f6 Mon Sep 17 00:00:00 2001 From: bob Date: Tue, 19 Mar 2019 15:50:54 -0400 Subject: started to integrate Northstar. changed server port to 4321. --- src/client/northstar/manager/Gateway.ts | 269 + .../northstar/model/idea/MetricTypeMapping.ts | 30 + src/client/northstar/model/idea/idea.ts | 8551 ++++++++++++++++++++ 3 files changed, 8850 insertions(+) create mode 100644 src/client/northstar/manager/Gateway.ts create mode 100644 src/client/northstar/model/idea/MetricTypeMapping.ts create mode 100644 src/client/northstar/model/idea/idea.ts (limited to 'src/client/northstar') diff --git a/src/client/northstar/manager/Gateway.ts b/src/client/northstar/manager/Gateway.ts new file mode 100644 index 000000000..5ae5e4f47 --- /dev/null +++ b/src/client/northstar/manager/Gateway.ts @@ -0,0 +1,269 @@ +import { Catalog, OperationReference, Result, CompileResults } from "../model/idea/idea" +import { computed, observable, action } from "mobx"; + +export class Gateway { + + private static _instance: Gateway; + + private constructor() { + } + + public static get Instance() { + return this._instance || (this._instance = new this()); + } + + public async GetCatalog(): Promise { + try { + const json = await this.MakeGetRequest("catalog"); + const cat = Catalog.fromJS(json); + return cat; + } + catch (error) { + throw new Error("can not reach northstar's backend"); + } + } + + public async ClearCatalog(): Promise { + try { + const json = await this.MakePostJsonRequest("Datamart/ClearAllAugmentations", {}); + } + catch (error) { + throw new Error("can not reach northstar's backend"); + } + } + + public async TerminateServer(): Promise { + try { + const url = Gateway.ConstructUrl("terminateServer"); + const response = await fetch(url, + { + redirect: "follow", + method: "POST", + credentials: "include" + }); + } + catch (error) { + throw new Error("can not reach northstar's backend"); + } + } + + public async Compile(data: any): Promise { + const json = await this.MakePostJsonRequest("compile", data); + if (json != null) { + const cr = CompileResults.fromJS(json); + return cr; + } + } + + public async SubmitResult(data: any): Promise { + try { + console.log(data); + const url = Gateway.ConstructUrl("submitProblem"); + const response = await fetch(url, + { + redirect: "follow", + method: "POST", + credentials: "include", + body: JSON.stringify(data) + }); + } + catch (error) { + throw new Error("can not reach northstar's backend"); + } + } + + public async SpecifyProblem(data: any): Promise { + try { + console.log(data); + const url = Gateway.ConstructUrl("specifyProblem"); + const response = await fetch(url, + { + redirect: "follow", + method: "POST", + credentials: "include", + body: JSON.stringify(data) + }); + } + catch (error) { + throw new Error("can not reach northstar's backend"); + } + } + + public async ExportToScript(solutionId: string): Promise { + try { + const url = Gateway.ConstructUrl("exportsolution/script/" + solutionId); + const response = await fetch(url, + { + redirect: "follow", + method: "GET", + credentials: "include" + }); + return await response.text(); + } + catch (error) { + throw new Error("can not reach northstar's backend"); + } + } + + + public async StartOperation(data: any): Promise { + const json = await this.MakePostJsonRequest("operation", data); + if (json != null) { + const or = OperationReference.fromJS(json); + return or; + } + } + + public async GetResult(data: any): Promise { + const json = await this.MakePostJsonRequest("result", data); + if (json != null) { + const res = Result.fromJS(json); + return res; + } + } + + public async PauseOperation(data: any): Promise { + const url = Gateway.ConstructUrl("pause"); + await fetch(url, + { + redirect: "follow", + method: "POST", + credentials: "include", + body: JSON.stringify(data) + }); + } + + public async MakeGetRequest(endpoint: string, signal?: AbortSignal): Promise { + const url = Gateway.ConstructUrl(endpoint); + const response = await fetch(url, + { + redirect: "follow", + method: "GET", + credentials: "include", + signal + }); + const json = await response.json(); + return json; + } + + public async MakePostJsonRequest(endpoint: string, data: any, signal?: AbortSignal): Promise { + const url = Gateway.ConstructUrl(endpoint); + const response = await fetch(url, + { + redirect: "follow", + method: "POST", + credentials: "include", + body: JSON.stringify(data), + signal + }); + const json = await response.json(); + return json; + } + + + public static ConstructUrl(appendix: string): string { + let base = Settings.Instance.ServerUrl; + if (base.slice(-1) == "/") { + base = base.slice(0, -1); + } + let url = base + "/" + Settings.Instance.ServerApiPath + "/" + appendix; + return url; + } +} + +declare var ENV: any; + +export class Settings { + private _environment: any; + + @observable + public ServerUrl: string = document.URL; + + @observable + public ServerApiPath?: string; + + @observable + public SampleSize?: number; + + @observable + public XBins?: number; + + @observable + public YBins?: number; + + @observable + public SplashTimeInMS?: number; + + @observable + public ShowFpsCounter?: boolean; + + @observable + public IsMenuFixed?: boolean; + + @observable + public ShowShutdownButton?: boolean; + + @observable + public IsDarpa?: boolean; + + @observable + public IsIGT?: boolean; + + @observable + public DegreeOfParallelism?: number; + + @observable + public ShowWarnings?: boolean; + + @computed + public get IsDev(): boolean { + return ENV.IsDev; + } + + @computed + public get TestDataFolderPath(): string { + return this.Origin + "testdata/"; + } + + @computed + public get Origin(): string { + return window.location.origin + "/"; + } + + private static _instance: Settings; + + @action + public Update(environment: any): void { + /*let serverParam = new URL(document.URL).searchParams.get("serverUrl"); + if (serverParam) { + if (serverParam === "debug") { + this.ServerUrl = `http://${window.location.hostname}:1234`; + } + else { + this.ServerUrl = serverParam; + } + } + else { + this.ServerUrl = environment["SERVER_URL"] ? environment["SERVER_URL"] : document.URL; + }*/ + this.ServerUrl = environment["SERVER_URL"] ? environment["SERVER_URL"] : document.URL; + this.ServerApiPath = environment["SERVER_API_PATH"]; + this.SampleSize = environment["SAMPLE_SIZE"]; + this.XBins = environment["X_BINS"]; + this.YBins = environment["Y_BINS"]; + this.SplashTimeInMS = environment["SPLASH_TIME_IN_MS"]; + this.ShowFpsCounter = environment["SHOW_FPS_COUNTER"]; + this.ShowShutdownButton = environment["SHOW_SHUTDOWN_BUTTON"]; + this.IsMenuFixed = environment["IS_MENU_FIXED"]; + this.IsDarpa = environment["IS_DARPA"]; + this.IsIGT = environment["IS_IGT"]; + this.DegreeOfParallelism = environment["DEGREE_OF_PARALLISM"]; + } + + public static get Instance(): Settings { + if (!this._instance) { + this._instance = new Settings(); + } + return this._instance; + } +} diff --git a/src/client/northstar/model/idea/MetricTypeMapping.ts b/src/client/northstar/model/idea/MetricTypeMapping.ts new file mode 100644 index 000000000..11e0c871a --- /dev/null +++ b/src/client/northstar/model/idea/MetricTypeMapping.ts @@ -0,0 +1,30 @@ +import { MetricType } from "./Idea"; +import { Dictionary } from 'typescript-collections'; + + +export class MetricTypeMapping { + + public static GetMetricInterpretation(metricType: MetricType): MetricInterpretation { + if (metricType == MetricType.Accuracy || + metricType == MetricType.F1 || + metricType == MetricType.F1Macro || + metricType == MetricType.F1Micro || + metricType == MetricType.JaccardSimilarityScore || + metricType == MetricType.ObjectDetectionAveragePrecision || + metricType == MetricType.Precision || + metricType == MetricType.PrecisionAtTopK || + metricType == MetricType.NormalizedMutualInformation || + metricType == MetricType.Recall || + metricType == MetricType.RocAucMacro || + metricType == MetricType.RocAuc || + metricType == MetricType.RocAucMicro || + metricType == MetricType.RSquared) { + return MetricInterpretation.HigherIsBetter; + } + return MetricInterpretation.LowerIsBetter; + } +} + +export enum MetricInterpretation { + HigherIsBetter, LowerIsBetter +} \ No newline at end of file diff --git a/src/client/northstar/model/idea/idea.ts b/src/client/northstar/model/idea/idea.ts new file mode 100644 index 000000000..9d9d60678 --- /dev/null +++ b/src/client/northstar/model/idea/idea.ts @@ -0,0 +1,8551 @@ +/* tslint:disable */ +//---------------------- +// +// Generated using the NSwag toolchain v11.19.2.0 (NJsonSchema v9.10.73.0 (Newtonsoft.Json v9.0.0.0)) (http://NSwag.org) +// +//---------------------- +// ReSharper disable InconsistentNaming + + + +export enum AggregateFunction { + None = "None", + Sum = "Sum", + SumE = "SumE", + Count = "Count", + Min = "Min", + Max = "Max", + Avg = "Avg", +} + +export abstract class AggregateParameters implements IAggregateParameters { + + protected _discriminator: string; + + constructor(data?: IAggregateParameters) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + this._discriminator = "AggregateParameters"; + } + + init(data?: any) { + if (data) { + } + } + + static fromJS(data: any): AggregateParameters { + data = typeof data === 'object' ? data : {}; + if (data["discriminator"] === "AverageAggregateParameters") { + let result = new AverageAggregateParameters(); + result.init(data); + return result; + } + if (data["discriminator"] === "SingleDimensionAggregateParameters") { + throw new Error("The abstract class 'SingleDimensionAggregateParameters' cannot be instantiated."); + } + if (data["discriminator"] === "CountAggregateParameters") { + let result = new CountAggregateParameters(); + result.init(data); + return result; + } + if (data["discriminator"] === "KDEAggregateParameters") { + let result = new KDEAggregateParameters(); + result.init(data); + return result; + } + if (data["discriminator"] === "MarginAggregateParameters") { + let result = new MarginAggregateParameters(); + result.init(data); + return result; + } + if (data["discriminator"] === "MaxAggregateParameters") { + let result = new MaxAggregateParameters(); + result.init(data); + return result; + } + if (data["discriminator"] === "MinAggregateParameters") { + let result = new MinAggregateParameters(); + result.init(data); + return result; + } + if (data["discriminator"] === "SumAggregateParameters") { + let result = new SumAggregateParameters(); + result.init(data); + return result; + } + if (data["discriminator"] === "SumEstimationAggregateParameters") { + let result = new SumEstimationAggregateParameters(); + result.init(data); + return result; + } + throw new Error("The abstract class 'AggregateParameters' cannot be instantiated."); + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["discriminator"] = this._discriminator; + return data; + } +} + +export interface IAggregateParameters { +} + +export abstract class SingleDimensionAggregateParameters extends AggregateParameters implements ISingleDimensionAggregateParameters { + attributeParameters?: AttributeParameters | undefined; + distinctAttributeParameters?: AttributeParameters | undefined; + + constructor(data?: ISingleDimensionAggregateParameters) { + super(data); + this._discriminator = "SingleDimensionAggregateParameters"; + } + + init(data?: any) { + super.init(data); + if (data) { + this.attributeParameters = data["AttributeParameters"] ? AttributeParameters.fromJS(data["AttributeParameters"]) : undefined; + this.distinctAttributeParameters = data["DistinctAttributeParameters"] ? AttributeParameters.fromJS(data["DistinctAttributeParameters"]) : undefined; + } + } + + static fromJS(data: any): SingleDimensionAggregateParameters { + data = typeof data === 'object' ? data : {}; + if (data["discriminator"] === "AverageAggregateParameters") { + let result = new AverageAggregateParameters(); + result.init(data); + return result; + } + if (data["discriminator"] === "CountAggregateParameters") { + let result = new CountAggregateParameters(); + result.init(data); + return result; + } + if (data["discriminator"] === "KDEAggregateParameters") { + let result = new KDEAggregateParameters(); + result.init(data); + return result; + } + if (data["discriminator"] === "MarginAggregateParameters") { + let result = new MarginAggregateParameters(); + result.init(data); + return result; + } + if (data["discriminator"] === "MaxAggregateParameters") { + let result = new MaxAggregateParameters(); + result.init(data); + return result; + } + if (data["discriminator"] === "MinAggregateParameters") { + let result = new MinAggregateParameters(); + result.init(data); + return result; + } + if (data["discriminator"] === "SumAggregateParameters") { + let result = new SumAggregateParameters(); + result.init(data); + return result; + } + if (data["discriminator"] === "SumEstimationAggregateParameters") { + let result = new SumEstimationAggregateParameters(); + result.init(data); + return result; + } + throw new Error("The abstract class 'SingleDimensionAggregateParameters' cannot be instantiated."); + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["AttributeParameters"] = this.attributeParameters ? this.attributeParameters.toJSON() : undefined; + data["DistinctAttributeParameters"] = this.distinctAttributeParameters ? this.distinctAttributeParameters.toJSON() : undefined; + super.toJSON(data); + return data; + } +} + +export interface ISingleDimensionAggregateParameters extends IAggregateParameters { + attributeParameters?: AttributeParameters | undefined; + distinctAttributeParameters?: AttributeParameters | undefined; +} + +export class AverageAggregateParameters extends SingleDimensionAggregateParameters implements IAverageAggregateParameters { + + constructor(data?: IAverageAggregateParameters) { + super(data); + this._discriminator = "AverageAggregateParameters"; + } + + init(data?: any) { + super.init(data); + if (data) { + } + } + + static fromJS(data: any): AverageAggregateParameters { + data = typeof data === 'object' ? data : {}; + let result = new AverageAggregateParameters(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + super.toJSON(data); + return data; + } +} + +export interface IAverageAggregateParameters extends ISingleDimensionAggregateParameters { +} + +export abstract class AttributeParameters implements IAttributeParameters { + visualizationHints?: VisualizationHint[] | undefined; + rawName?: string | undefined; + + protected _discriminator: string; + + constructor(data?: IAttributeParameters) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + this._discriminator = "AttributeParameters"; + } + + init(data?: any) { + if (data) { + if (data["VisualizationHints"] && data["VisualizationHints"].constructor === Array) { + this.visualizationHints = []; + for (let item of data["VisualizationHints"]) + this.visualizationHints.push(item); + } + this.rawName = data["RawName"]; + } + } + + static fromJS(data: any): AttributeParameters { + data = typeof data === 'object' ? data : {}; + if (data["discriminator"] === "AttributeBackendParameters") { + let result = new AttributeBackendParameters(); + result.init(data); + return result; + } + if (data["discriminator"] === "AttributeCaclculatedParameters") { + throw new Error("The abstract class 'AttributeCaclculatedParameters' cannot be instantiated."); + } + if (data["discriminator"] === "AttributeCodeParameters") { + let result = new AttributeCodeParameters(); + result.init(data); + return result; + } + if (data["discriminator"] === "AttributeColumnParameters") { + let result = new AttributeColumnParameters(); + result.init(data); + return result; + } + throw new Error("The abstract class 'AttributeParameters' cannot be instantiated."); + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["discriminator"] = this._discriminator; + if (this.visualizationHints && this.visualizationHints.constructor === Array) { + data["VisualizationHints"] = []; + for (let item of this.visualizationHints) + data["VisualizationHints"].push(item); + } + data["RawName"] = this.rawName; + return data; + } +} + +export interface IAttributeParameters { + visualizationHints?: VisualizationHint[] | undefined; + rawName?: string | undefined; +} + +export enum VisualizationHint { + TreatAsEnumeration = "TreatAsEnumeration", + DefaultFlipAxis = "DefaultFlipAxis", + Image = "Image", +} + +export abstract class AttributeCaclculatedParameters extends AttributeParameters implements IAttributeCaclculatedParameters { + + constructor(data?: IAttributeCaclculatedParameters) { + super(data); + this._discriminator = "AttributeCaclculatedParameters"; + } + + init(data?: any) { + super.init(data); + if (data) { + } + } + + static fromJS(data: any): AttributeCaclculatedParameters { + data = typeof data === 'object' ? data : {}; + if (data["discriminator"] === "AttributeBackendParameters") { + let result = new AttributeBackendParameters(); + result.init(data); + return result; + } + if (data["discriminator"] === "AttributeCodeParameters") { + let result = new AttributeCodeParameters(); + result.init(data); + return result; + } + throw new Error("The abstract class 'AttributeCaclculatedParameters' cannot be instantiated."); + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + super.toJSON(data); + return data; + } +} + +export interface IAttributeCaclculatedParameters extends IAttributeParameters { +} + +export class AttributeBackendParameters extends AttributeCaclculatedParameters implements IAttributeBackendParameters { + id?: string | undefined; + + constructor(data?: IAttributeBackendParameters) { + super(data); + this._discriminator = "AttributeBackendParameters"; + } + + init(data?: any) { + super.init(data); + if (data) { + this.id = data["Id"]; + } + } + + static fromJS(data: any): AttributeBackendParameters { + data = typeof data === 'object' ? data : {}; + let result = new AttributeBackendParameters(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["Id"] = this.id; + super.toJSON(data); + return data; + } +} + +export interface IAttributeBackendParameters extends IAttributeCaclculatedParameters { + id?: string | undefined; +} + +export class AttributeCodeParameters extends AttributeCaclculatedParameters implements IAttributeCodeParameters { + code?: string | undefined; + + constructor(data?: IAttributeCodeParameters) { + super(data); + this._discriminator = "AttributeCodeParameters"; + } + + init(data?: any) { + super.init(data); + if (data) { + this.code = data["Code"]; + } + } + + static fromJS(data: any): AttributeCodeParameters { + data = typeof data === 'object' ? data : {}; + let result = new AttributeCodeParameters(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["Code"] = this.code; + super.toJSON(data); + return data; + } +} + +export interface IAttributeCodeParameters extends IAttributeCaclculatedParameters { + code?: string | undefined; +} + +export class AttributeColumnParameters extends AttributeParameters implements IAttributeColumnParameters { + + constructor(data?: IAttributeColumnParameters) { + super(data); + this._discriminator = "AttributeColumnParameters"; + } + + init(data?: any) { + super.init(data); + if (data) { + } + } + + static fromJS(data: any): AttributeColumnParameters { + data = typeof data === 'object' ? data : {}; + let result = new AttributeColumnParameters(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + super.toJSON(data); + return data; + } +} + +export interface IAttributeColumnParameters extends IAttributeParameters { +} + +export class CountAggregateParameters extends SingleDimensionAggregateParameters implements ICountAggregateParameters { + + constructor(data?: ICountAggregateParameters) { + super(data); + this._discriminator = "CountAggregateParameters"; + } + + init(data?: any) { + super.init(data); + if (data) { + } + } + + static fromJS(data: any): CountAggregateParameters { + data = typeof data === 'object' ? data : {}; + let result = new CountAggregateParameters(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + super.toJSON(data); + return data; + } +} + +export interface ICountAggregateParameters extends ISingleDimensionAggregateParameters { +} + +export class KDEAggregateParameters extends SingleDimensionAggregateParameters implements IKDEAggregateParameters { + nrOfSamples?: number | undefined; + + constructor(data?: IKDEAggregateParameters) { + super(data); + this._discriminator = "KDEAggregateParameters"; + } + + init(data?: any) { + super.init(data); + if (data) { + this.nrOfSamples = data["NrOfSamples"]; + } + } + + static fromJS(data: any): KDEAggregateParameters { + data = typeof data === 'object' ? data : {}; + let result = new KDEAggregateParameters(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["NrOfSamples"] = this.nrOfSamples; + super.toJSON(data); + return data; + } +} + +export interface IKDEAggregateParameters extends ISingleDimensionAggregateParameters { + nrOfSamples?: number | undefined; +} + +export class MarginAggregateParameters extends SingleDimensionAggregateParameters implements IMarginAggregateParameters { + aggregateFunction?: AggregateFunction | undefined; + + constructor(data?: IMarginAggregateParameters) { + super(data); + this._discriminator = "MarginAggregateParameters"; + } + + init(data?: any) { + super.init(data); + if (data) { + this.aggregateFunction = data["AggregateFunction"]; + } + } + + static fromJS(data: any): MarginAggregateParameters { + data = typeof data === 'object' ? data : {}; + let result = new MarginAggregateParameters(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["AggregateFunction"] = this.aggregateFunction; + super.toJSON(data); + return data; + } +} + +export interface IMarginAggregateParameters extends ISingleDimensionAggregateParameters { + aggregateFunction?: AggregateFunction | undefined; +} + +export class MaxAggregateParameters extends SingleDimensionAggregateParameters implements IMaxAggregateParameters { + + constructor(data?: IMaxAggregateParameters) { + super(data); + this._discriminator = "MaxAggregateParameters"; + } + + init(data?: any) { + super.init(data); + if (data) { + } + } + + static fromJS(data: any): MaxAggregateParameters { + data = typeof data === 'object' ? data : {}; + let result = new MaxAggregateParameters(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + super.toJSON(data); + return data; + } +} + +export interface IMaxAggregateParameters extends ISingleDimensionAggregateParameters { +} + +export class MinAggregateParameters extends SingleDimensionAggregateParameters implements IMinAggregateParameters { + + constructor(data?: IMinAggregateParameters) { + super(data); + this._discriminator = "MinAggregateParameters"; + } + + init(data?: any) { + super.init(data); + if (data) { + } + } + + static fromJS(data: any): MinAggregateParameters { + data = typeof data === 'object' ? data : {}; + let result = new MinAggregateParameters(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + super.toJSON(data); + return data; + } +} + +export interface IMinAggregateParameters extends ISingleDimensionAggregateParameters { +} + +export class SumAggregateParameters extends SingleDimensionAggregateParameters implements ISumAggregateParameters { + + constructor(data?: ISumAggregateParameters) { + super(data); + this._discriminator = "SumAggregateParameters"; + } + + init(data?: any) { + super.init(data); + if (data) { + } + } + + static fromJS(data: any): SumAggregateParameters { + data = typeof data === 'object' ? data : {}; + let result = new SumAggregateParameters(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + super.toJSON(data); + return data; + } +} + +export interface ISumAggregateParameters extends ISingleDimensionAggregateParameters { +} + +export class SumEstimationAggregateParameters extends SingleDimensionAggregateParameters implements ISumEstimationAggregateParameters { + + constructor(data?: ISumEstimationAggregateParameters) { + super(data); + this._discriminator = "SumEstimationAggregateParameters"; + } + + init(data?: any) { + super.init(data); + if (data) { + } + } + + static fromJS(data: any): SumEstimationAggregateParameters { + data = typeof data === 'object' ? data : {}; + let result = new SumEstimationAggregateParameters(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + super.toJSON(data); + return data; + } +} + +export interface ISumEstimationAggregateParameters extends ISingleDimensionAggregateParameters { +} + +export enum OrderingFunction { + None = 0, + SortUp = 1, + SortDown = 2, +} + +export abstract class BinningParameters implements IBinningParameters { + attributeParameters?: AttributeParameters | undefined; + + protected _discriminator: string; + + constructor(data?: IBinningParameters) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + this._discriminator = "BinningParameters"; + } + + init(data?: any) { + if (data) { + this.attributeParameters = data["AttributeParameters"] ? AttributeParameters.fromJS(data["AttributeParameters"]) : undefined; + } + } + + static fromJS(data: any): BinningParameters { + data = typeof data === 'object' ? data : {}; + if (data["discriminator"] === "EquiWidthBinningParameters") { + let result = new EquiWidthBinningParameters(); + result.init(data); + return result; + } + if (data["discriminator"] === "SingleBinBinningParameters") { + let result = new SingleBinBinningParameters(); + result.init(data); + return result; + } + throw new Error("The abstract class 'BinningParameters' cannot be instantiated."); + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["discriminator"] = this._discriminator; + data["AttributeParameters"] = this.attributeParameters ? this.attributeParameters.toJSON() : undefined; + return data; + } +} + +export interface IBinningParameters { + attributeParameters?: AttributeParameters | undefined; +} + +export class EquiWidthBinningParameters extends BinningParameters implements IEquiWidthBinningParameters { + minValue?: number | undefined; + maxValue?: number | undefined; + requestedNrOfBins?: number | undefined; + referenceValue?: number | undefined; + step?: number | undefined; + + constructor(data?: IEquiWidthBinningParameters) { + super(data); + this._discriminator = "EquiWidthBinningParameters"; + } + + init(data?: any) { + super.init(data); + if (data) { + this.minValue = data["MinValue"]; + this.maxValue = data["MaxValue"]; + this.requestedNrOfBins = data["RequestedNrOfBins"]; + this.referenceValue = data["ReferenceValue"]; + this.step = data["Step"]; + } + } + + static fromJS(data: any): EquiWidthBinningParameters { + data = typeof data === 'object' ? data : {}; + let result = new EquiWidthBinningParameters(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["MinValue"] = this.minValue; + data["MaxValue"] = this.maxValue; + data["RequestedNrOfBins"] = this.requestedNrOfBins; + data["ReferenceValue"] = this.referenceValue; + data["Step"] = this.step; + super.toJSON(data); + return data; + } +} + +export interface IEquiWidthBinningParameters extends IBinningParameters { + minValue?: number | undefined; + maxValue?: number | undefined; + requestedNrOfBins?: number | undefined; + referenceValue?: number | undefined; + step?: number | undefined; +} + +export class SingleBinBinningParameters extends BinningParameters implements ISingleBinBinningParameters { + + constructor(data?: ISingleBinBinningParameters) { + super(data); + this._discriminator = "SingleBinBinningParameters"; + } + + init(data?: any) { + super.init(data); + if (data) { + } + } + + static fromJS(data: any): SingleBinBinningParameters { + data = typeof data === 'object' ? data : {}; + let result = new SingleBinBinningParameters(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + super.toJSON(data); + return data; + } +} + +export interface ISingleBinBinningParameters extends IBinningParameters { +} + +export class Attribute implements IAttribute { + displayName?: string | undefined; + rawName?: string | undefined; + description?: string | undefined; + dataType?: DataType | undefined; + visualizationHints?: VisualizationHint[] | undefined; + isTarget?: boolean | undefined; + + constructor(data?: IAttribute) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(data?: any) { + if (data) { + this.displayName = data["DisplayName"]; + this.rawName = data["RawName"]; + this.description = data["Description"]; + this.dataType = data["DataType"]; + if (data["VisualizationHints"] && data["VisualizationHints"].constructor === Array) { + this.visualizationHints = []; + for (let item of data["VisualizationHints"]) + this.visualizationHints.push(item); + } + this.isTarget = data["IsTarget"]; + } + } + + static fromJS(data: any): Attribute { + data = typeof data === 'object' ? data : {}; + let result = new Attribute(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["DisplayName"] = this.displayName; + data["RawName"] = this.rawName; + data["Description"] = this.description; + data["DataType"] = this.dataType; + if (this.visualizationHints && this.visualizationHints.constructor === Array) { + data["VisualizationHints"] = []; + for (let item of this.visualizationHints) + data["VisualizationHints"].push(item); + } + data["IsTarget"] = this.isTarget; + return data; + } +} + +export interface IAttribute { + displayName?: string | undefined; + rawName?: string | undefined; + description?: string | undefined; + dataType?: DataType | undefined; + visualizationHints?: VisualizationHint[] | undefined; + isTarget?: boolean | undefined; +} + +export enum DataType { + Int = "Int", + String = "String", + Float = "Float", + Double = "Double", + DateTime = "DateTime", + Object = "Object", + Undefined = "Undefined", +} + +export class AttributeGroup implements IAttributeGroup { + name?: string | undefined; + attributeGroups?: AttributeGroup[] | undefined; + attributes?: Attribute[] | undefined; + + constructor(data?: IAttributeGroup) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(data?: any) { + if (data) { + this.name = data["Name"]; + if (data["AttributeGroups"] && data["AttributeGroups"].constructor === Array) { + this.attributeGroups = []; + for (let item of data["AttributeGroups"]) + this.attributeGroups.push(AttributeGroup.fromJS(item)); + } + if (data["Attributes"] && data["Attributes"].constructor === Array) { + this.attributes = []; + for (let item of data["Attributes"]) + this.attributes.push(Attribute.fromJS(item)); + } + } + } + + static fromJS(data: any): AttributeGroup { + data = typeof data === 'object' ? data : {}; + let result = new AttributeGroup(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["Name"] = this.name; + if (this.attributeGroups && this.attributeGroups.constructor === Array) { + data["AttributeGroups"] = []; + for (let item of this.attributeGroups) + data["AttributeGroups"].push(item.toJSON()); + } + if (this.attributes && this.attributes.constructor === Array) { + data["Attributes"] = []; + for (let item of this.attributes) + data["Attributes"].push(item.toJSON()); + } + return data; + } +} + +export interface IAttributeGroup { + name?: string | undefined; + attributeGroups?: AttributeGroup[] | undefined; + attributes?: Attribute[] | undefined; +} + +export class Catalog implements ICatalog { + supportedOperations?: string[] | undefined; + schemas?: Schema[] | undefined; + + constructor(data?: ICatalog) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(data?: any) { + if (data) { + if (data["SupportedOperations"] && data["SupportedOperations"].constructor === Array) { + this.supportedOperations = []; + for (let item of data["SupportedOperations"]) + this.supportedOperations.push(item); + } + if (data["Schemas"] && data["Schemas"].constructor === Array) { + this.schemas = []; + for (let item of data["Schemas"]) + this.schemas.push(Schema.fromJS(item)); + } + } + } + + static fromJS(data: any): Catalog { + data = typeof data === 'object' ? data : {}; + let result = new Catalog(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + if (this.supportedOperations && this.supportedOperations.constructor === Array) { + data["SupportedOperations"] = []; + for (let item of this.supportedOperations) + data["SupportedOperations"].push(item); + } + if (this.schemas && this.schemas.constructor === Array) { + data["Schemas"] = []; + for (let item of this.schemas) + data["Schemas"].push(item.toJSON()); + } + return data; + } +} + +export interface ICatalog { + supportedOperations?: string[] | undefined; + schemas?: Schema[] | undefined; +} + +export class Schema implements ISchema { + rootAttributeGroup?: AttributeGroup | undefined; + displayName?: string | undefined; + augmentedFrom?: string | undefined; + rawName?: string | undefined; + problemDescription?: string | undefined; + darpaProblemDoc?: DarpaProblemDoc | undefined; + distinctAttributeParameters?: AttributeParameters | undefined; + darpaDatasetDoc?: DarpaDatasetDoc | undefined; + darpaDatasetLocation?: string | undefined; + isMultiResourceData?: boolean | undefined; + problemFinderRows?: ProblemFinderRows[] | undefined; + correlationRows?: ProblemFinderRows[] | undefined; + + constructor(data?: ISchema) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(data?: any) { + if (data) { + this.rootAttributeGroup = data["RootAttributeGroup"] ? AttributeGroup.fromJS(data["RootAttributeGroup"]) : undefined; + this.displayName = data["DisplayName"]; + this.augmentedFrom = data["AugmentedFrom"]; + this.rawName = data["RawName"]; + this.problemDescription = data["ProblemDescription"]; + this.darpaProblemDoc = data["DarpaProblemDoc"] ? DarpaProblemDoc.fromJS(data["DarpaProblemDoc"]) : undefined; + this.distinctAttributeParameters = data["DistinctAttributeParameters"] ? AttributeParameters.fromJS(data["DistinctAttributeParameters"]) : undefined; + this.darpaDatasetDoc = data["DarpaDatasetDoc"] ? DarpaDatasetDoc.fromJS(data["DarpaDatasetDoc"]) : undefined; + this.darpaDatasetLocation = data["DarpaDatasetLocation"]; + this.isMultiResourceData = data["IsMultiResourceData"]; + if (data["ProblemFinderRows"] && data["ProblemFinderRows"].constructor === Array) { + this.problemFinderRows = []; + for (let item of data["ProblemFinderRows"]) + this.problemFinderRows.push(ProblemFinderRows.fromJS(item)); + } + if (data["CorrelationRows"] && data["CorrelationRows"].constructor === Array) { + this.correlationRows = []; + for (let item of data["CorrelationRows"]) + this.correlationRows.push(ProblemFinderRows.fromJS(item)); + } + } + } + + static fromJS(data: any): Schema { + data = typeof data === 'object' ? data : {}; + let result = new Schema(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["RootAttributeGroup"] = this.rootAttributeGroup ? this.rootAttributeGroup.toJSON() : undefined; + data["DisplayName"] = this.displayName; + data["AugmentedFrom"] = this.augmentedFrom; + data["RawName"] = this.rawName; + data["ProblemDescription"] = this.problemDescription; + data["DarpaProblemDoc"] = this.darpaProblemDoc ? this.darpaProblemDoc.toJSON() : undefined; + data["DistinctAttributeParameters"] = this.distinctAttributeParameters ? this.distinctAttributeParameters.toJSON() : undefined; + data["DarpaDatasetDoc"] = this.darpaDatasetDoc ? this.darpaDatasetDoc.toJSON() : undefined; + data["DarpaDatasetLocation"] = this.darpaDatasetLocation; + data["IsMultiResourceData"] = this.isMultiResourceData; + if (this.problemFinderRows && this.problemFinderRows.constructor === Array) { + data["ProblemFinderRows"] = []; + for (let item of this.problemFinderRows) + data["ProblemFinderRows"].push(item.toJSON()); + } + if (this.correlationRows && this.correlationRows.constructor === Array) { + data["CorrelationRows"] = []; + for (let item of this.correlationRows) + data["CorrelationRows"].push(item.toJSON()); + } + return data; + } +} + +export interface ISchema { + rootAttributeGroup?: AttributeGroup | undefined; + displayName?: string | undefined; + augmentedFrom?: string | undefined; + rawName?: string | undefined; + problemDescription?: string | undefined; + darpaProblemDoc?: DarpaProblemDoc | undefined; + distinctAttributeParameters?: AttributeParameters | undefined; + darpaDatasetDoc?: DarpaDatasetDoc | undefined; + darpaDatasetLocation?: string | undefined; + isMultiResourceData?: boolean | undefined; + problemFinderRows?: ProblemFinderRows[] | undefined; + correlationRows?: ProblemFinderRows[] | undefined; +} + +export class DarpaProblemDoc implements IDarpaProblemDoc { + about?: ProblemAbout | undefined; + inputs?: ProblemInputs | undefined; + + constructor(data?: IDarpaProblemDoc) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(data?: any) { + if (data) { + this.about = data["about"] ? ProblemAbout.fromJS(data["about"]) : undefined; + this.inputs = data["inputs"] ? ProblemInputs.fromJS(data["inputs"]) : undefined; + } + } + + static fromJS(data: any): DarpaProblemDoc { + data = typeof data === 'object' ? data : {}; + let result = new DarpaProblemDoc(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["about"] = this.about ? this.about.toJSON() : undefined; + data["inputs"] = this.inputs ? this.inputs.toJSON() : undefined; + return data; + } +} + +export interface IDarpaProblemDoc { + about?: ProblemAbout | undefined; + inputs?: ProblemInputs | undefined; +} + +export class ProblemAbout implements IProblemAbout { + problemID?: string | undefined; + problemName?: string | undefined; + problemDescription?: string | undefined; + taskType?: string | undefined; + taskSubType?: string | undefined; + problemSchemaVersion?: string | undefined; + problemVersion?: string | undefined; + + constructor(data?: IProblemAbout) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(data?: any) { + if (data) { + this.problemID = data["problemID"]; + this.problemName = data["problemName"]; + this.problemDescription = data["problemDescription"]; + this.taskType = data["taskType"]; + this.taskSubType = data["taskSubType"]; + this.problemSchemaVersion = data["problemSchemaVersion"]; + this.problemVersion = data["problemVersion"]; + } + } + + static fromJS(data: any): ProblemAbout { + data = typeof data === 'object' ? data : {}; + let result = new ProblemAbout(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["problemID"] = this.problemID; + data["problemName"] = this.problemName; + data["problemDescription"] = this.problemDescription; + data["taskType"] = this.taskType; + data["taskSubType"] = this.taskSubType; + data["problemSchemaVersion"] = this.problemSchemaVersion; + data["problemVersion"] = this.problemVersion; + return data; + } +} + +export interface IProblemAbout { + problemID?: string | undefined; + problemName?: string | undefined; + problemDescription?: string | undefined; + taskType?: string | undefined; + taskSubType?: string | undefined; + problemSchemaVersion?: string | undefined; + problemVersion?: string | undefined; +} + +export class ProblemInputs implements IProblemInputs { + data?: ProblemData[] | undefined; + performanceMetrics?: ProblemPerformanceMetric[] | undefined; + + constructor(data?: IProblemInputs) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(data?: any) { + if (data) { + if (data["data"] && data["data"].constructor === Array) { + this.data = []; + for (let item of data["data"]) + this.data.push(ProblemData.fromJS(item)); + } + if (data["performanceMetrics"] && data["performanceMetrics"].constructor === Array) { + this.performanceMetrics = []; + for (let item of data["performanceMetrics"]) + this.performanceMetrics.push(ProblemPerformanceMetric.fromJS(item)); + } + } + } + + static fromJS(data: any): ProblemInputs { + data = typeof data === 'object' ? data : {}; + let result = new ProblemInputs(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + if (this.data && this.data.constructor === Array) { + data["data"] = []; + for (let item of this.data) + data["data"].push(item.toJSON()); + } + if (this.performanceMetrics && this.performanceMetrics.constructor === Array) { + data["performanceMetrics"] = []; + for (let item of this.performanceMetrics) + data["performanceMetrics"].push(item.toJSON()); + } + return data; + } +} + +export interface IProblemInputs { + data?: ProblemData[] | undefined; + performanceMetrics?: ProblemPerformanceMetric[] | undefined; +} + +export class ProblemData implements IProblemData { + datasetID?: string | undefined; + targets?: ProblemTarget[] | undefined; + + constructor(data?: IProblemData) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(data?: any) { + if (data) { + this.datasetID = data["datasetID"]; + if (data["targets"] && data["targets"].constructor === Array) { + this.targets = []; + for (let item of data["targets"]) + this.targets.push(ProblemTarget.fromJS(item)); + } + } + } + + static fromJS(data: any): ProblemData { + data = typeof data === 'object' ? data : {}; + let result = new ProblemData(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["datasetID"] = this.datasetID; + if (this.targets && this.targets.constructor === Array) { + data["targets"] = []; + for (let item of this.targets) + data["targets"].push(item.toJSON()); + } + return data; + } +} + +export interface IProblemData { + datasetID?: string | undefined; + targets?: ProblemTarget[] | undefined; +} + +export class ProblemTarget implements IProblemTarget { + targetIndex?: number | undefined; + resID?: string | undefined; + colIndex?: number | undefined; + colName?: string | undefined; + + constructor(data?: IProblemTarget) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(data?: any) { + if (data) { + this.targetIndex = data["targetIndex"]; + this.resID = data["resID"]; + this.colIndex = data["colIndex"]; + this.colName = data["colName"]; + } + } + + static fromJS(data: any): ProblemTarget { + data = typeof data === 'object' ? data : {}; + let result = new ProblemTarget(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["targetIndex"] = this.targetIndex; + data["resID"] = this.resID; + data["colIndex"] = this.colIndex; + data["colName"] = this.colName; + return data; + } +} + +export interface IProblemTarget { + targetIndex?: number | undefined; + resID?: string | undefined; + colIndex?: number | undefined; + colName?: string | undefined; +} + +export class ProblemPerformanceMetric implements IProblemPerformanceMetric { + metric?: string | undefined; + + constructor(data?: IProblemPerformanceMetric) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(data?: any) { + if (data) { + this.metric = data["metric"]; + } + } + + static fromJS(data: any): ProblemPerformanceMetric { + data = typeof data === 'object' ? data : {}; + let result = new ProblemPerformanceMetric(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["metric"] = this.metric; + return data; + } +} + +export interface IProblemPerformanceMetric { + metric?: string | undefined; +} + +export class DarpaDatasetDoc implements IDarpaDatasetDoc { + about?: DatasetAbout | undefined; + dataResources?: Resource[] | undefined; + + constructor(data?: IDarpaDatasetDoc) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(data?: any) { + if (data) { + this.about = data["about"] ? DatasetAbout.fromJS(data["about"]) : undefined; + if (data["dataResources"] && data["dataResources"].constructor === Array) { + this.dataResources = []; + for (let item of data["dataResources"]) + this.dataResources.push(Resource.fromJS(item)); + } + } + } + + static fromJS(data: any): DarpaDatasetDoc { + data = typeof data === 'object' ? data : {}; + let result = new DarpaDatasetDoc(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["about"] = this.about ? this.about.toJSON() : undefined; + if (this.dataResources && this.dataResources.constructor === Array) { + data["dataResources"] = []; + for (let item of this.dataResources) + data["dataResources"].push(item.toJSON()); + } + return data; + } +} + +export interface IDarpaDatasetDoc { + about?: DatasetAbout | undefined; + dataResources?: Resource[] | undefined; +} + +export class DatasetAbout implements IDatasetAbout { + datasetID?: string | undefined; + datasetName?: string | undefined; + description?: string | undefined; + citation?: string | undefined; + license?: string | undefined; + source?: string | undefined; + sourceURI?: string | undefined; + approximateSize?: string | undefined; + datasetSchemaVersion?: string | undefined; + redacted?: boolean | undefined; + datasetVersion?: string | undefined; + + constructor(data?: IDatasetAbout) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(data?: any) { + if (data) { + this.datasetID = data["datasetID"]; + this.datasetName = data["datasetName"]; + this.description = data["description"]; + this.citation = data["citation"]; + this.license = data["license"]; + this.source = data["source"]; + this.sourceURI = data["sourceURI"]; + this.approximateSize = data["approximateSize"]; + this.datasetSchemaVersion = data["datasetSchemaVersion"]; + this.redacted = data["redacted"]; + this.datasetVersion = data["datasetVersion"]; + } + } + + static fromJS(data: any): DatasetAbout { + data = typeof data === 'object' ? data : {}; + let result = new DatasetAbout(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["datasetID"] = this.datasetID; + data["datasetName"] = this.datasetName; + data["description"] = this.description; + data["citation"] = this.citation; + data["license"] = this.license; + data["source"] = this.source; + data["sourceURI"] = this.sourceURI; + data["approximateSize"] = this.approximateSize; + data["datasetSchemaVersion"] = this.datasetSchemaVersion; + data["redacted"] = this.redacted; + data["datasetVersion"] = this.datasetVersion; + return data; + } +} + +export interface IDatasetAbout { + datasetID?: string | undefined; + datasetName?: string | undefined; + description?: string | undefined; + citation?: string | undefined; + license?: string | undefined; + source?: string | undefined; + sourceURI?: string | undefined; + approximateSize?: string | undefined; + datasetSchemaVersion?: string | undefined; + redacted?: boolean | undefined; + datasetVersion?: string | undefined; +} + +export class Resource implements IResource { + resID?: string | undefined; + resPath?: string | undefined; + resType?: string | undefined; + resFormat?: string[] | undefined; + columns?: Column[] | undefined; + isCollection?: boolean | undefined; + + constructor(data?: IResource) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(data?: any) { + if (data) { + this.resID = data["resID"]; + this.resPath = data["resPath"]; + this.resType = data["resType"]; + if (data["resFormat"] && data["resFormat"].constructor === Array) { + this.resFormat = []; + for (let item of data["resFormat"]) + this.resFormat.push(item); + } + if (data["columns"] && data["columns"].constructor === Array) { + this.columns = []; + for (let item of data["columns"]) + this.columns.push(Column.fromJS(item)); + } + this.isCollection = data["isCollection"]; + } + } + + static fromJS(data: any): Resource { + data = typeof data === 'object' ? data : {}; + let result = new Resource(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["resID"] = this.resID; + data["resPath"] = this.resPath; + data["resType"] = this.resType; + if (this.resFormat && this.resFormat.constructor === Array) { + data["resFormat"] = []; + for (let item of this.resFormat) + data["resFormat"].push(item); + } + if (this.columns && this.columns.constructor === Array) { + data["columns"] = []; + for (let item of this.columns) + data["columns"].push(item.toJSON()); + } + data["isCollection"] = this.isCollection; + return data; + } +} + +export interface IResource { + resID?: string | undefined; + resPath?: string | undefined; + resType?: string | undefined; + resFormat?: string[] | undefined; + columns?: Column[] | undefined; + isCollection?: boolean | undefined; +} + +export class Column implements IColumn { + colIndex?: number | undefined; + colDescription?: string | undefined; + colName?: string | undefined; + colType?: string | undefined; + role?: string[] | undefined; + refersTo?: Reference | undefined; + + constructor(data?: IColumn) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(data?: any) { + if (data) { + this.colIndex = data["colIndex"]; + this.colDescription = data["colDescription"]; + this.colName = data["colName"]; + this.colType = data["colType"]; + if (data["role"] && data["role"].constructor === Array) { + this.role = []; + for (let item of data["role"]) + this.role.push(item); + } + this.refersTo = data["refersTo"] ? Reference.fromJS(data["refersTo"]) : undefined; + } + } + + static fromJS(data: any): Column { + data = typeof data === 'object' ? data : {}; + let result = new Column(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["colIndex"] = this.colIndex; + data["colDescription"] = this.colDescription; + data["colName"] = this.colName; + data["colType"] = this.colType; + if (this.role && this.role.constructor === Array) { + data["role"] = []; + for (let item of this.role) + data["role"].push(item); + } + data["refersTo"] = this.refersTo ? this.refersTo.toJSON() : undefined; + return data; + } +} + +export interface IColumn { + colIndex?: number | undefined; + colDescription?: string | undefined; + colName?: string | undefined; + colType?: string | undefined; + role?: string[] | undefined; + refersTo?: Reference | undefined; +} + +export class Reference implements IReference { + resID?: string | undefined; + + constructor(data?: IReference) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(data?: any) { + if (data) { + this.resID = data["resID"]; + } + } + + static fromJS(data: any): Reference { + data = typeof data === 'object' ? data : {}; + let result = new Reference(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["resID"] = this.resID; + return data; + } +} + +export interface IReference { + resID?: string | undefined; +} + +export class ProblemFinderRows implements IProblemFinderRows { + label?: string | undefined; + type?: string | undefined; + features?: Feature[] | undefined; + + constructor(data?: IProblemFinderRows) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(data?: any) { + if (data) { + this.label = data["label"]; + this.type = data["type"]; + if (data["features"] && data["features"].constructor === Array) { + this.features = []; + for (let item of data["features"]) + this.features.push(Feature.fromJS(item)); + } + } + } + + static fromJS(data: any): ProblemFinderRows { + data = typeof data === 'object' ? data : {}; + let result = new ProblemFinderRows(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["label"] = this.label; + data["type"] = this.type; + if (this.features && this.features.constructor === Array) { + data["features"] = []; + for (let item of this.features) + data["features"].push(item.toJSON()); + } + return data; + } +} + +export interface IProblemFinderRows { + label?: string | undefined; + type?: string | undefined; + features?: Feature[] | undefined; +} + +export class Feature implements IFeature { + name?: string | undefined; + selected?: boolean | undefined; + value?: number | undefined; + + constructor(data?: IFeature) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(data?: any) { + if (data) { + this.name = data["name"]; + this.selected = data["selected"]; + this.value = data["value"]; + } + } + + static fromJS(data: any): Feature { + data = typeof data === 'object' ? data : {}; + let result = new Feature(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["name"] = this.name; + data["selected"] = this.selected; + data["value"] = this.value; + return data; + } +} + +export interface IFeature { + name?: string | undefined; + selected?: boolean | undefined; + value?: number | undefined; +} + +export enum DataType2 { + Int = 0, + String = 1, + Float = 2, + Double = 3, + DateTime = 4, + Object = 5, + Undefined = 6, +} + +export abstract class DataTypeExtensions implements IDataTypeExtensions { + + constructor(data?: IDataTypeExtensions) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(data?: any) { + if (data) { + } + } + + static fromJS(data: any): DataTypeExtensions { + data = typeof data === 'object' ? data : {}; + throw new Error("The abstract class 'DataTypeExtensions' cannot be instantiated."); + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + return data; + } +} + +export interface IDataTypeExtensions { +} + +export class ResObject implements IResObject { + columnName?: string | undefined; + + constructor(data?: IResObject) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(data?: any) { + if (data) { + this.columnName = data["columnName"]; + } + } + + static fromJS(data: any): ResObject { + data = typeof data === 'object' ? data : {}; + let result = new ResObject(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["columnName"] = this.columnName; + return data; + } +} + +export interface IResObject { + columnName?: string | undefined; +} + +export class Exception implements IException { + message?: string | undefined; + innerException?: Exception | undefined; + stackTrace?: string | undefined; + source?: string | undefined; + + constructor(data?: IException) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(data?: any) { + if (data) { + this.message = data["Message"]; + this.innerException = data["InnerException"] ? Exception.fromJS(data["InnerException"]) : undefined; + this.stackTrace = data["StackTrace"]; + this.source = data["Source"]; + } + } + + static fromJS(data: any): Exception { + data = typeof data === 'object' ? data : {}; + let result = new Exception(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["Message"] = this.message; + data["InnerException"] = this.innerException ? this.innerException.toJSON() : undefined; + data["StackTrace"] = this.stackTrace; + data["Source"] = this.source; + return data; + } +} + +export interface IException { + message?: string | undefined; + innerException?: Exception | undefined; + stackTrace?: string | undefined; + source?: string | undefined; +} + +export class IDEAException extends Exception implements IIDEAException { + + constructor(data?: IIDEAException) { + super(data); + } + + init(data?: any) { + super.init(data); + if (data) { + } + } + + static fromJS(data: any): IDEAException { + data = typeof data === 'object' ? data : {}; + let result = new IDEAException(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + super.toJSON(data); + return data; + } +} + +export interface IIDEAException extends IException { +} + +export class CodeParameters implements ICodeParameters { + attributeCodeParameters?: AttributeCodeParameters[] | undefined; + adapterName?: string | undefined; + + constructor(data?: ICodeParameters) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(data?: any) { + if (data) { + if (data["AttributeCodeParameters"] && data["AttributeCodeParameters"].constructor === Array) { + this.attributeCodeParameters = []; + for (let item of data["AttributeCodeParameters"]) + this.attributeCodeParameters.push(AttributeCodeParameters.fromJS(item)); + } + this.adapterName = data["AdapterName"]; + } + } + + static fromJS(data: any): CodeParameters { + data = typeof data === 'object' ? data : {}; + let result = new CodeParameters(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + if (this.attributeCodeParameters && this.attributeCodeParameters.constructor === Array) { + data["AttributeCodeParameters"] = []; + for (let item of this.attributeCodeParameters) + data["AttributeCodeParameters"].push(item.toJSON()); + } + data["AdapterName"] = this.adapterName; + return data; + } +} + +export interface ICodeParameters { + attributeCodeParameters?: AttributeCodeParameters[] | undefined; + adapterName?: string | undefined; +} + +export class CompileResult implements ICompileResult { + compileSuccess?: boolean | undefined; + compileMessage?: string | undefined; + dataType?: DataType | undefined; + replaceAttributeParameters?: AttributeParameters[] | undefined; + + constructor(data?: ICompileResult) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(data?: any) { + if (data) { + this.compileSuccess = data["CompileSuccess"]; + this.compileMessage = data["CompileMessage"]; + this.dataType = data["DataType"]; + if (data["ReplaceAttributeParameters"] && data["ReplaceAttributeParameters"].constructor === Array) { + this.replaceAttributeParameters = []; + for (let item of data["ReplaceAttributeParameters"]) + this.replaceAttributeParameters.push(AttributeParameters.fromJS(item)); + } + } + } + + static fromJS(data: any): CompileResult { + data = typeof data === 'object' ? data : {}; + let result = new CompileResult(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["CompileSuccess"] = this.compileSuccess; + data["CompileMessage"] = this.compileMessage; + data["DataType"] = this.dataType; + if (this.replaceAttributeParameters && this.replaceAttributeParameters.constructor === Array) { + data["ReplaceAttributeParameters"] = []; + for (let item of this.replaceAttributeParameters) + data["ReplaceAttributeParameters"].push(item.toJSON()); + } + return data; + } +} + +export interface ICompileResult { + compileSuccess?: boolean | undefined; + compileMessage?: string | undefined; + dataType?: DataType | undefined; + replaceAttributeParameters?: AttributeParameters[] | undefined; +} + +export class CompileResults implements ICompileResults { + rawNameToCompileResult?: { [key: string]: CompileResult; } | undefined; + + constructor(data?: ICompileResults) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(data?: any) { + if (data) { + if (data["RawNameToCompileResult"]) { + this.rawNameToCompileResult = {}; + for (let key in data["RawNameToCompileResult"]) { + if (data["RawNameToCompileResult"].hasOwnProperty(key)) + this.rawNameToCompileResult[key] = data["RawNameToCompileResult"][key] ? CompileResult.fromJS(data["RawNameToCompileResult"][key]) : new CompileResult(); + } + } + } + } + + static fromJS(data: any): CompileResults { + data = typeof data === 'object' ? data : {}; + let result = new CompileResults(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + if (this.rawNameToCompileResult) { + data["RawNameToCompileResult"] = {}; + for (let key in this.rawNameToCompileResult) { + if (this.rawNameToCompileResult.hasOwnProperty(key)) + data["RawNameToCompileResult"][key] = this.rawNameToCompileResult[key]; + } + } + return data; + } +} + +export interface ICompileResults { + rawNameToCompileResult?: { [key: string]: CompileResult; } | undefined; +} + +export abstract class UniqueJson implements IUniqueJson { + + constructor(data?: IUniqueJson) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(data?: any) { + if (data) { + } + } + + static fromJS(data: any): UniqueJson { + data = typeof data === 'object' ? data : {}; + throw new Error("The abstract class 'UniqueJson' cannot be instantiated."); + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + return data; + } +} + +export interface IUniqueJson { +} + +export abstract class OperationParameters extends UniqueJson implements IOperationParameters { + isCachable?: boolean | undefined; + + protected _discriminator: string; + + constructor(data?: IOperationParameters) { + super(data); + this._discriminator = "OperationParameters"; + } + + init(data?: any) { + super.init(data); + if (data) { + this.isCachable = data["IsCachable"]; + } + } + + static fromJS(data: any): OperationParameters { + data = typeof data === 'object' ? data : {}; + if (data["discriminator"] === "DataOperationParameters") { + throw new Error("The abstract class 'DataOperationParameters' cannot be instantiated."); + } + if (data["discriminator"] === "ExampleOperationParameters") { + let result = new ExampleOperationParameters(); + result.init(data); + return result; + } + if (data["discriminator"] === "HistogramOperationParameters") { + let result = new HistogramOperationParameters(); + result.init(data); + return result; + } + if (data["discriminator"] === "DistOperationParameters") { + throw new Error("The abstract class 'DistOperationParameters' cannot be instantiated."); + } + if (data["discriminator"] === "OptimizerOperationParameters") { + let result = new OptimizerOperationParameters(); + result.init(data); + return result; + } + if (data["discriminator"] === "RawDataOperationParameters") { + let result = new RawDataOperationParameters(); + result.init(data); + return result; + } + if (data["discriminator"] === "RecommenderOperationParameters") { + let result = new RecommenderOperationParameters(); + result.init(data); + return result; + } + if (data["discriminator"] === "CDFOperationParameters") { + let result = new CDFOperationParameters(); + result.init(data); + return result; + } + if (data["discriminator"] === "TestDistOperationParameters") { + throw new Error("The abstract class 'TestDistOperationParameters' cannot be instantiated."); + } + if (data["discriminator"] === "ChiSquaredTestOperationParameters") { + let result = new ChiSquaredTestOperationParameters(); + result.init(data); + return result; + } + if (data["discriminator"] === "HypothesisTestParameters") { + throw new Error("The abstract class 'HypothesisTestParameters' cannot be instantiated."); + } + if (data["discriminator"] === "CorrelationTestOperationParameters") { + let result = new CorrelationTestOperationParameters(); + result.init(data); + return result; + } + if (data["discriminator"] === "EmpiricalDistOperationParameters") { + let result = new EmpiricalDistOperationParameters(); + result.init(data); + return result; + } + if (data["discriminator"] === "KSTestOperationParameters") { + let result = new KSTestOperationParameters(); + result.init(data); + return result; + } + if (data["discriminator"] === "NewModelOperationParameters") { + let result = new NewModelOperationParameters(); + result.init(data); + return result; + } + if (data["discriminator"] === "ModelOperationParameters") { + throw new Error("The abstract class 'ModelOperationParameters' cannot be instantiated."); + } + if (data["discriminator"] === "RootMeanSquareTestOperationParameters") { + let result = new RootMeanSquareTestOperationParameters(); + result.init(data); + return result; + } + if (data["discriminator"] === "TTestOperationParameters") { + let result = new TTestOperationParameters(); + result.init(data); + return result; + } + if (data["discriminator"] === "FeatureImportanceOperationParameters") { + let result = new FeatureImportanceOperationParameters(); + result.init(data); + return result; + } + if (data["discriminator"] === "SampleOperationParameters") { + let result = new SampleOperationParameters(); + result.init(data); + return result; + } + if (data["discriminator"] === "AddComparisonParameters") { + let result = new AddComparisonParameters(); + result.init(data); + return result; + } + if (data["discriminator"] === "GetModelStateParameters") { + let result = new GetModelStateParameters(); + result.init(data); + return result; + } + if (data["discriminator"] === "FrequentItemsetOperationParameters") { + let result = new FrequentItemsetOperationParameters(); + result.init(data); + return result; + } + throw new Error("The abstract class 'OperationParameters' cannot be instantiated."); + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["discriminator"] = this._discriminator; + data["IsCachable"] = this.isCachable; + super.toJSON(data); + return data; + } +} + +export interface IOperationParameters extends IUniqueJson { + isCachable?: boolean | undefined; +} + +export abstract class DataOperationParameters extends OperationParameters implements IDataOperationParameters { + sampleStreamBlockSize?: number | undefined; + adapterName?: string | undefined; + isCachable?: boolean | undefined; + + constructor(data?: IDataOperationParameters) { + super(data); + this._discriminator = "DataOperationParameters"; + } + + init(data?: any) { + super.init(data); + if (data) { + this.sampleStreamBlockSize = data["SampleStreamBlockSize"]; + this.adapterName = data["AdapterName"]; + this.isCachable = data["IsCachable"]; + } + } + + static fromJS(data: any): DataOperationParameters { + data = typeof data === 'object' ? data : {}; + if (data["discriminator"] === "ExampleOperationParameters") { + let result = new ExampleOperationParameters(); + result.init(data); + return result; + } + if (data["discriminator"] === "HistogramOperationParameters") { + let result = new HistogramOperationParameters(); + result.init(data); + return result; + } + if (data["discriminator"] === "DistOperationParameters") { + throw new Error("The abstract class 'DistOperationParameters' cannot be instantiated."); + } + if (data["discriminator"] === "OptimizerOperationParameters") { + let result = new OptimizerOperationParameters(); + result.init(data); + return result; + } + if (data["discriminator"] === "RawDataOperationParameters") { + let result = new RawDataOperationParameters(); + result.init(data); + return result; + } + if (data["discriminator"] === "RecommenderOperationParameters") { + let result = new RecommenderOperationParameters(); + result.init(data); + return result; + } + if (data["discriminator"] === "CDFOperationParameters") { + let result = new CDFOperationParameters(); + result.init(data); + return result; + } + if (data["discriminator"] === "TestDistOperationParameters") { + throw new Error("The abstract class 'TestDistOperationParameters' cannot be instantiated."); + } + if (data["discriminator"] === "EmpiricalDistOperationParameters") { + let result = new EmpiricalDistOperationParameters(); + result.init(data); + return result; + } + if (data["discriminator"] === "FeatureImportanceOperationParameters") { + let result = new FeatureImportanceOperationParameters(); + result.init(data); + return result; + } + if (data["discriminator"] === "SampleOperationParameters") { + let result = new SampleOperationParameters(); + result.init(data); + return result; + } + if (data["discriminator"] === "FrequentItemsetOperationParameters") { + let result = new FrequentItemsetOperationParameters(); + result.init(data); + return result; + } + throw new Error("The abstract class 'DataOperationParameters' cannot be instantiated."); + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["SampleStreamBlockSize"] = this.sampleStreamBlockSize; + data["AdapterName"] = this.adapterName; + data["IsCachable"] = this.isCachable; + super.toJSON(data); + return data; + } +} + +export interface IDataOperationParameters extends IOperationParameters { + sampleStreamBlockSize?: number | undefined; + adapterName?: string | undefined; + isCachable?: boolean | undefined; +} + +export class ExampleOperationParameters extends DataOperationParameters implements IExampleOperationParameters { + filter?: string | undefined; + attributeParameters?: AttributeParameters[] | undefined; + attributeCodeParameters?: AttributeCaclculatedParameters[] | undefined; + dummyValue?: number | undefined; + exampleType?: string | undefined; + + constructor(data?: IExampleOperationParameters) { + super(data); + this._discriminator = "ExampleOperationParameters"; + } + + init(data?: any) { + super.init(data); + if (data) { + this.filter = data["Filter"]; + if (data["AttributeParameters"] && data["AttributeParameters"].constructor === Array) { + this.attributeParameters = []; + for (let item of data["AttributeParameters"]) + this.attributeParameters.push(AttributeParameters.fromJS(item)); + } + if (data["AttributeCodeParameters"] && data["AttributeCodeParameters"].constructor === Array) { + this.attributeCodeParameters = []; + for (let item of data["AttributeCodeParameters"]) + this.attributeCodeParameters.push(AttributeCaclculatedParameters.fromJS(item)); + } + this.dummyValue = data["DummyValue"]; + this.exampleType = data["ExampleType"]; + } + } + + static fromJS(data: any): ExampleOperationParameters { + data = typeof data === 'object' ? data : {}; + let result = new ExampleOperationParameters(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["Filter"] = this.filter; + if (this.attributeParameters && this.attributeParameters.constructor === Array) { + data["AttributeParameters"] = []; + for (let item of this.attributeParameters) + data["AttributeParameters"].push(item.toJSON()); + } + if (this.attributeCodeParameters && this.attributeCodeParameters.constructor === Array) { + data["AttributeCodeParameters"] = []; + for (let item of this.attributeCodeParameters) + data["AttributeCodeParameters"].push(item.toJSON()); + } + data["DummyValue"] = this.dummyValue; + data["ExampleType"] = this.exampleType; + super.toJSON(data); + return data; + } +} + +export interface IExampleOperationParameters extends IDataOperationParameters { + filter?: string | undefined; + attributeParameters?: AttributeParameters[] | undefined; + attributeCodeParameters?: AttributeCaclculatedParameters[] | undefined; + dummyValue?: number | undefined; + exampleType?: string | undefined; +} + +export abstract class DistOperationParameters extends DataOperationParameters implements IDistOperationParameters { + filter?: string | undefined; + attributeCalculatedParameters?: AttributeCaclculatedParameters[] | undefined; + + constructor(data?: IDistOperationParameters) { + super(data); + this._discriminator = "DistOperationParameters"; + } + + init(data?: any) { + super.init(data); + if (data) { + this.filter = data["Filter"]; + if (data["AttributeCalculatedParameters"] && data["AttributeCalculatedParameters"].constructor === Array) { + this.attributeCalculatedParameters = []; + for (let item of data["AttributeCalculatedParameters"]) + this.attributeCalculatedParameters.push(AttributeCaclculatedParameters.fromJS(item)); + } + } + } + + static fromJS(data: any): DistOperationParameters { + data = typeof data === 'object' ? data : {}; + if (data["discriminator"] === "HistogramOperationParameters") { + let result = new HistogramOperationParameters(); + result.init(data); + return result; + } + if (data["discriminator"] === "OptimizerOperationParameters") { + let result = new OptimizerOperationParameters(); + result.init(data); + return result; + } + if (data["discriminator"] === "RawDataOperationParameters") { + let result = new RawDataOperationParameters(); + result.init(data); + return result; + } + if (data["discriminator"] === "CDFOperationParameters") { + let result = new CDFOperationParameters(); + result.init(data); + return result; + } + if (data["discriminator"] === "TestDistOperationParameters") { + throw new Error("The abstract class 'TestDistOperationParameters' cannot be instantiated."); + } + if (data["discriminator"] === "EmpiricalDistOperationParameters") { + let result = new EmpiricalDistOperationParameters(); + result.init(data); + return result; + } + if (data["discriminator"] === "FeatureImportanceOperationParameters") { + let result = new FeatureImportanceOperationParameters(); + result.init(data); + return result; + } + if (data["discriminator"] === "SampleOperationParameters") { + let result = new SampleOperationParameters(); + result.init(data); + return result; + } + if (data["discriminator"] === "FrequentItemsetOperationParameters") { + let result = new FrequentItemsetOperationParameters(); + result.init(data); + return result; + } + throw new Error("The abstract class 'DistOperationParameters' cannot be instantiated."); + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["Filter"] = this.filter; + if (this.attributeCalculatedParameters && this.attributeCalculatedParameters.constructor === Array) { + data["AttributeCalculatedParameters"] = []; + for (let item of this.attributeCalculatedParameters) + data["AttributeCalculatedParameters"].push(item.toJSON()); + } + super.toJSON(data); + return data; + } +} + +export interface IDistOperationParameters extends IDataOperationParameters { + filter?: string | undefined; + attributeCalculatedParameters?: AttributeCaclculatedParameters[] | undefined; +} + +export class HistogramOperationParameters extends DistOperationParameters implements IHistogramOperationParameters { + sortPerBinAggregateParameter?: AggregateParameters | undefined; + binningParameters?: BinningParameters[] | undefined; + perBinAggregateParameters?: AggregateParameters[] | undefined; + globalAggregateParameters?: AggregateParameters[] | undefined; + brushes?: string[] | undefined; + enableBrushComputation?: boolean | undefined; + degreeOfParallism?: number | undefined; + + constructor(data?: IHistogramOperationParameters) { + super(data); + this._discriminator = "HistogramOperationParameters"; + } + + init(data?: any) { + super.init(data); + if (data) { + this.sortPerBinAggregateParameter = data["SortPerBinAggregateParameter"] ? AggregateParameters.fromJS(data["SortPerBinAggregateParameter"]) : undefined; + if (data["BinningParameters"] && data["BinningParameters"].constructor === Array) { + this.binningParameters = []; + for (let item of data["BinningParameters"]) + this.binningParameters.push(BinningParameters.fromJS(item)); + } + if (data["PerBinAggregateParameters"] && data["PerBinAggregateParameters"].constructor === Array) { + this.perBinAggregateParameters = []; + for (let item of data["PerBinAggregateParameters"]) + this.perBinAggregateParameters.push(AggregateParameters.fromJS(item)); + } + if (data["GlobalAggregateParameters"] && data["GlobalAggregateParameters"].constructor === Array) { + this.globalAggregateParameters = []; + for (let item of data["GlobalAggregateParameters"]) + this.globalAggregateParameters.push(AggregateParameters.fromJS(item)); + } + if (data["Brushes"] && data["Brushes"].constructor === Array) { + this.brushes = []; + for (let item of data["Brushes"]) + this.brushes.push(item); + } + this.enableBrushComputation = data["EnableBrushComputation"]; + this.degreeOfParallism = data["DegreeOfParallism"]; + } + } + + static fromJS(data: any): HistogramOperationParameters { + data = typeof data === 'object' ? data : {}; + let result = new HistogramOperationParameters(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["SortPerBinAggregateParameter"] = this.sortPerBinAggregateParameter ? this.sortPerBinAggregateParameter.toJSON() : undefined; + if (this.binningParameters && this.binningParameters.constructor === Array) { + data["BinningParameters"] = []; + for (let item of this.binningParameters) + data["BinningParameters"].push(item.toJSON()); + } + if (this.perBinAggregateParameters && this.perBinAggregateParameters.constructor === Array) { + data["PerBinAggregateParameters"] = []; + for (let item of this.perBinAggregateParameters) + data["PerBinAggregateParameters"].push(item.toJSON()); + } + if (this.globalAggregateParameters && this.globalAggregateParameters.constructor === Array) { + data["GlobalAggregateParameters"] = []; + for (let item of this.globalAggregateParameters) + data["GlobalAggregateParameters"].push(item.toJSON()); + } + if (this.brushes && this.brushes.constructor === Array) { + data["Brushes"] = []; + for (let item of this.brushes) + data["Brushes"].push(item); + } + data["EnableBrushComputation"] = this.enableBrushComputation; + data["DegreeOfParallism"] = this.degreeOfParallism; + super.toJSON(data); + return data; + } +} + +export interface IHistogramOperationParameters extends IDistOperationParameters { + sortPerBinAggregateParameter?: AggregateParameters | undefined; + binningParameters?: BinningParameters[] | undefined; + perBinAggregateParameters?: AggregateParameters[] | undefined; + globalAggregateParameters?: AggregateParameters[] | undefined; + brushes?: string[] | undefined; + enableBrushComputation?: boolean | undefined; + degreeOfParallism?: number | undefined; +} + +export class OptimizerOperationParameters extends DistOperationParameters implements IOptimizerOperationParameters { + taskType?: TaskType | undefined; + taskSubType?: TaskSubType | undefined; + metricType?: MetricType | undefined; + labelAttribute?: AttributeParameters | undefined; + featureAttributes?: AttributeParameters[] | undefined; + requiredPrimitives?: string[] | undefined; + pythonFilter?: string | undefined; + trainFilter?: string | undefined; + pythonTrainFilter?: string | undefined; + testFilter?: string | undefined; + pythonTestFilter?: string | undefined; + + constructor(data?: IOptimizerOperationParameters) { + super(data); + this._discriminator = "OptimizerOperationParameters"; + } + + init(data?: any) { + super.init(data); + if (data) { + this.taskType = data["TaskType"]; + this.taskSubType = data["TaskSubType"]; + this.metricType = data["MetricType"]; + this.labelAttribute = data["LabelAttribute"] ? AttributeParameters.fromJS(data["LabelAttribute"]) : undefined; + if (data["FeatureAttributes"] && data["FeatureAttributes"].constructor === Array) { + this.featureAttributes = []; + for (let item of data["FeatureAttributes"]) + this.featureAttributes.push(AttributeParameters.fromJS(item)); + } + if (data["RequiredPrimitives"] && data["RequiredPrimitives"].constructor === Array) { + this.requiredPrimitives = []; + for (let item of data["RequiredPrimitives"]) + this.requiredPrimitives.push(item); + } + this.pythonFilter = data["PythonFilter"]; + this.trainFilter = data["TrainFilter"]; + this.pythonTrainFilter = data["PythonTrainFilter"]; + this.testFilter = data["TestFilter"]; + this.pythonTestFilter = data["PythonTestFilter"]; + } + } + + static fromJS(data: any): OptimizerOperationParameters { + data = typeof data === 'object' ? data : {}; + let result = new OptimizerOperationParameters(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["TaskType"] = this.taskType; + data["TaskSubType"] = this.taskSubType; + data["MetricType"] = this.metricType; + data["LabelAttribute"] = this.labelAttribute ? this.labelAttribute.toJSON() : undefined; + if (this.featureAttributes && this.featureAttributes.constructor === Array) { + data["FeatureAttributes"] = []; + for (let item of this.featureAttributes) + data["FeatureAttributes"].push(item.toJSON()); + } + if (this.requiredPrimitives && this.requiredPrimitives.constructor === Array) { + data["RequiredPrimitives"] = []; + for (let item of this.requiredPrimitives) + data["RequiredPrimitives"].push(item); + } + data["PythonFilter"] = this.pythonFilter; + data["TrainFilter"] = this.trainFilter; + data["PythonTrainFilter"] = this.pythonTrainFilter; + data["TestFilter"] = this.testFilter; + data["PythonTestFilter"] = this.pythonTestFilter; + super.toJSON(data); + return data; + } +} + +export interface IOptimizerOperationParameters extends IDistOperationParameters { + taskType?: TaskType | undefined; + taskSubType?: TaskSubType | undefined; + metricType?: MetricType | undefined; + labelAttribute?: AttributeParameters | undefined; + featureAttributes?: AttributeParameters[] | undefined; + requiredPrimitives?: string[] | undefined; + pythonFilter?: string | undefined; + trainFilter?: string | undefined; + pythonTrainFilter?: string | undefined; + testFilter?: string | undefined; + pythonTestFilter?: string | undefined; +} + +export enum TaskType { + Undefined = 0, + Classification = 1, + Regression = 2, + Clustering = 3, + LinkPrediction = 4, + VertexNomination = 5, + CommunityDetection = 6, + GraphClustering = 7, + GraphMatching = 8, + TimeSeriesForecasting = 9, + CollaborativeFiltering = 10, +} + +export enum TaskSubType { + Undefined = 0, + None = 1, + Binary = 2, + Multiclass = 3, + Multilabel = 4, + Univariate = 5, + Multivariate = 6, + Overlapping = 7, + Nonoverlapping = 8, +} + +export enum MetricType { + MetricUndefined = 0, + Accuracy = 1, + Precision = 2, + Recall = 3, + F1 = 4, + F1Micro = 5, + F1Macro = 6, + RocAuc = 7, + RocAucMicro = 8, + RocAucMacro = 9, + MeanSquaredError = 10, + RootMeanSquaredError = 11, + RootMeanSquaredErrorAvg = 12, + MeanAbsoluteError = 13, + RSquared = 14, + NormalizedMutualInformation = 15, + JaccardSimilarityScore = 16, + PrecisionAtTopK = 17, + ObjectDetectionAveragePrecision = 18, + Loss = 100, +} + +export class RawDataOperationParameters extends DistOperationParameters implements IRawDataOperationParameters { + sortUpRawName?: string | undefined; + sortDownRawName?: string | undefined; + numRecords?: number | undefined; + binningParameters?: BinningParameters[] | undefined; + brushes?: string[] | undefined; + enableBrushComputation?: boolean | undefined; + + constructor(data?: IRawDataOperationParameters) { + super(data); + this._discriminator = "RawDataOperationParameters"; + } + + init(data?: any) { + super.init(data); + if (data) { + this.sortUpRawName = data["SortUpRawName"]; + this.sortDownRawName = data["SortDownRawName"]; + this.numRecords = data["NumRecords"]; + if (data["BinningParameters"] && data["BinningParameters"].constructor === Array) { + this.binningParameters = []; + for (let item of data["BinningParameters"]) + this.binningParameters.push(BinningParameters.fromJS(item)); + } + if (data["Brushes"] && data["Brushes"].constructor === Array) { + this.brushes = []; + for (let item of data["Brushes"]) + this.brushes.push(item); + } + this.enableBrushComputation = data["EnableBrushComputation"]; + } + } + + static fromJS(data: any): RawDataOperationParameters { + data = typeof data === 'object' ? data : {}; + let result = new RawDataOperationParameters(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["SortUpRawName"] = this.sortUpRawName; + data["SortDownRawName"] = this.sortDownRawName; + data["NumRecords"] = this.numRecords; + if (this.binningParameters && this.binningParameters.constructor === Array) { + data["BinningParameters"] = []; + for (let item of this.binningParameters) + data["BinningParameters"].push(item.toJSON()); + } + if (this.brushes && this.brushes.constructor === Array) { + data["Brushes"] = []; + for (let item of this.brushes) + data["Brushes"].push(item); + } + data["EnableBrushComputation"] = this.enableBrushComputation; + super.toJSON(data); + return data; + } +} + +export interface IRawDataOperationParameters extends IDistOperationParameters { + sortUpRawName?: string | undefined; + sortDownRawName?: string | undefined; + numRecords?: number | undefined; + binningParameters?: BinningParameters[] | undefined; + brushes?: string[] | undefined; + enableBrushComputation?: boolean | undefined; +} + +export class RecommenderOperationParameters extends DataOperationParameters implements IRecommenderOperationParameters { + target?: HistogramOperationParameters | undefined; + budget?: number | undefined; + modelId?: ModelId | undefined; + includeAttributeParameters?: AttributeParameters[] | undefined; + excludeAttributeParameters?: AttributeParameters[] | undefined; + riskControlType?: RiskControlType | undefined; + + constructor(data?: IRecommenderOperationParameters) { + super(data); + this._discriminator = "RecommenderOperationParameters"; + } + + init(data?: any) { + super.init(data); + if (data) { + this.target = data["Target"] ? HistogramOperationParameters.fromJS(data["Target"]) : undefined; + this.budget = data["Budget"]; + this.modelId = data["ModelId"] ? ModelId.fromJS(data["ModelId"]) : undefined; + if (data["IncludeAttributeParameters"] && data["IncludeAttributeParameters"].constructor === Array) { + this.includeAttributeParameters = []; + for (let item of data["IncludeAttributeParameters"]) + this.includeAttributeParameters.push(AttributeParameters.fromJS(item)); + } + if (data["ExcludeAttributeParameters"] && data["ExcludeAttributeParameters"].constructor === Array) { + this.excludeAttributeParameters = []; + for (let item of data["ExcludeAttributeParameters"]) + this.excludeAttributeParameters.push(AttributeParameters.fromJS(item)); + } + this.riskControlType = data["RiskControlType"]; + } + } + + static fromJS(data: any): RecommenderOperationParameters { + data = typeof data === 'object' ? data : {}; + let result = new RecommenderOperationParameters(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["Target"] = this.target ? this.target.toJSON() : undefined; + data["Budget"] = this.budget; + data["ModelId"] = this.modelId ? this.modelId.toJSON() : undefined; + if (this.includeAttributeParameters && this.includeAttributeParameters.constructor === Array) { + data["IncludeAttributeParameters"] = []; + for (let item of this.includeAttributeParameters) + data["IncludeAttributeParameters"].push(item.toJSON()); + } + if (this.excludeAttributeParameters && this.excludeAttributeParameters.constructor === Array) { + data["ExcludeAttributeParameters"] = []; + for (let item of this.excludeAttributeParameters) + data["ExcludeAttributeParameters"].push(item.toJSON()); + } + data["RiskControlType"] = this.riskControlType; + super.toJSON(data); + return data; + } +} + +export interface IRecommenderOperationParameters extends IDataOperationParameters { + target?: HistogramOperationParameters | undefined; + budget?: number | undefined; + modelId?: ModelId | undefined; + includeAttributeParameters?: AttributeParameters[] | undefined; + excludeAttributeParameters?: AttributeParameters[] | undefined; + riskControlType?: RiskControlType | undefined; +} + +export class ModelId implements IModelId { + value?: string | undefined; + + constructor(data?: IModelId) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(data?: any) { + if (data) { + this.value = data["Value"]; + } + } + + static fromJS(data: any): ModelId { + data = typeof data === 'object' ? data : {}; + let result = new ModelId(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["Value"] = this.value; + return data; + } +} + +export interface IModelId { + value?: string | undefined; +} + +export enum RiskControlType { + PCER = 0, + Bonferroni = 1, + AdaBonferroni = 2, + HolmBonferroni = 3, + BHFDR = 4, + SeqFDR = 5, + AlphaFDR = 6, + BestFootForward = 7, + BetaFarsighted = 8, + BetaFarsightedWithSupport = 9, + GammaFixed = 10, + DeltaHopeful = 11, + EpsilonHybrid = 12, + EpsilonHybridWithoutSupport = 13, + PsiSupport = 14, + ZetaDynamic = 15, + Unknown = 16, +} + +export abstract class TestDistOperationParameters extends DistOperationParameters implements ITestDistOperationParameters { + attributeParameters?: AttributeParameters[] | undefined; + + constructor(data?: ITestDistOperationParameters) { + super(data); + this._discriminator = "TestDistOperationParameters"; + } + + init(data?: any) { + super.init(data); + if (data) { + if (data["AttributeParameters"] && data["AttributeParameters"].constructor === Array) { + this.attributeParameters = []; + for (let item of data["AttributeParameters"]) + this.attributeParameters.push(AttributeParameters.fromJS(item)); + } + } + } + + static fromJS(data: any): TestDistOperationParameters { + data = typeof data === 'object' ? data : {}; + if (data["discriminator"] === "CDFOperationParameters") { + let result = new CDFOperationParameters(); + result.init(data); + return result; + } + if (data["discriminator"] === "EmpiricalDistOperationParameters") { + let result = new EmpiricalDistOperationParameters(); + result.init(data); + return result; + } + throw new Error("The abstract class 'TestDistOperationParameters' cannot be instantiated."); + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + if (this.attributeParameters && this.attributeParameters.constructor === Array) { + data["AttributeParameters"] = []; + for (let item of this.attributeParameters) + data["AttributeParameters"].push(item.toJSON()); + } + super.toJSON(data); + return data; + } +} + +export interface ITestDistOperationParameters extends IDistOperationParameters { + attributeParameters?: AttributeParameters[] | undefined; +} + +export class CDFOperationParameters extends TestDistOperationParameters implements ICDFOperationParameters { + + constructor(data?: ICDFOperationParameters) { + super(data); + this._discriminator = "CDFOperationParameters"; + } + + init(data?: any) { + super.init(data); + if (data) { + } + } + + static fromJS(data: any): CDFOperationParameters { + data = typeof data === 'object' ? data : {}; + let result = new CDFOperationParameters(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + super.toJSON(data); + return data; + } +} + +export interface ICDFOperationParameters extends ITestDistOperationParameters { +} + +export abstract class HypothesisTestParameters extends OperationParameters implements IHypothesisTestParameters { + childOperationParameters?: OperationParameters[] | undefined; + isCachable?: boolean | undefined; + + constructor(data?: IHypothesisTestParameters) { + super(data); + this._discriminator = "HypothesisTestParameters"; + } + + init(data?: any) { + super.init(data); + if (data) { + if (data["ChildOperationParameters"] && data["ChildOperationParameters"].constructor === Array) { + this.childOperationParameters = []; + for (let item of data["ChildOperationParameters"]) + this.childOperationParameters.push(OperationParameters.fromJS(item)); + } + this.isCachable = data["IsCachable"]; + } + } + + static fromJS(data: any): HypothesisTestParameters { + data = typeof data === 'object' ? data : {}; + if (data["discriminator"] === "ChiSquaredTestOperationParameters") { + let result = new ChiSquaredTestOperationParameters(); + result.init(data); + return result; + } + if (data["discriminator"] === "CorrelationTestOperationParameters") { + let result = new CorrelationTestOperationParameters(); + result.init(data); + return result; + } + if (data["discriminator"] === "KSTestOperationParameters") { + let result = new KSTestOperationParameters(); + result.init(data); + return result; + } + if (data["discriminator"] === "RootMeanSquareTestOperationParameters") { + let result = new RootMeanSquareTestOperationParameters(); + result.init(data); + return result; + } + if (data["discriminator"] === "TTestOperationParameters") { + let result = new TTestOperationParameters(); + result.init(data); + return result; + } + throw new Error("The abstract class 'HypothesisTestParameters' cannot be instantiated."); + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + if (this.childOperationParameters && this.childOperationParameters.constructor === Array) { + data["ChildOperationParameters"] = []; + for (let item of this.childOperationParameters) + data["ChildOperationParameters"].push(item.toJSON()); + } + data["IsCachable"] = this.isCachable; + super.toJSON(data); + return data; + } +} + +export interface IHypothesisTestParameters extends IOperationParameters { + childOperationParameters?: OperationParameters[] | undefined; + isCachable?: boolean | undefined; +} + +export class ChiSquaredTestOperationParameters extends HypothesisTestParameters implements IChiSquaredTestOperationParameters { + + constructor(data?: IChiSquaredTestOperationParameters) { + super(data); + this._discriminator = "ChiSquaredTestOperationParameters"; + } + + init(data?: any) { + super.init(data); + if (data) { + } + } + + static fromJS(data: any): ChiSquaredTestOperationParameters { + data = typeof data === 'object' ? data : {}; + let result = new ChiSquaredTestOperationParameters(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + super.toJSON(data); + return data; + } +} + +export interface IChiSquaredTestOperationParameters extends IHypothesisTestParameters { +} + +export class CorrelationTestOperationParameters extends HypothesisTestParameters implements ICorrelationTestOperationParameters { + + constructor(data?: ICorrelationTestOperationParameters) { + super(data); + this._discriminator = "CorrelationTestOperationParameters"; + } + + init(data?: any) { + super.init(data); + if (data) { + } + } + + static fromJS(data: any): CorrelationTestOperationParameters { + data = typeof data === 'object' ? data : {}; + let result = new CorrelationTestOperationParameters(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + super.toJSON(data); + return data; + } +} + +export interface ICorrelationTestOperationParameters extends IHypothesisTestParameters { +} + +export class SubmitProblemParameters implements ISubmitProblemParameters { + id?: string | undefined; + + constructor(data?: ISubmitProblemParameters) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(data?: any) { + if (data) { + this.id = data["Id"]; + } + } + + static fromJS(data: any): SubmitProblemParameters { + data = typeof data === 'object' ? data : {}; + let result = new SubmitProblemParameters(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["Id"] = this.id; + return data; + } +} + +export interface ISubmitProblemParameters { + id?: string | undefined; +} + +export class SpecifyProblemParameters implements ISpecifyProblemParameters { + id?: string | undefined; + userComment?: string | undefined; + optimizerOperationParameters?: OptimizerOperationParameters | undefined; + + constructor(data?: ISpecifyProblemParameters) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(data?: any) { + if (data) { + this.id = data["Id"]; + this.userComment = data["UserComment"]; + this.optimizerOperationParameters = data["OptimizerOperationParameters"] ? OptimizerOperationParameters.fromJS(data["OptimizerOperationParameters"]) : undefined; + } + } + + static fromJS(data: any): SpecifyProblemParameters { + data = typeof data === 'object' ? data : {}; + let result = new SpecifyProblemParameters(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["Id"] = this.id; + data["UserComment"] = this.userComment; + data["OptimizerOperationParameters"] = this.optimizerOperationParameters ? this.optimizerOperationParameters.toJSON() : undefined; + return data; + } +} + +export interface ISpecifyProblemParameters { + id?: string | undefined; + userComment?: string | undefined; + optimizerOperationParameters?: OptimizerOperationParameters | undefined; +} + +export class EmpiricalDistOperationParameters extends TestDistOperationParameters implements IEmpiricalDistOperationParameters { + keepSamples?: boolean | undefined; + + constructor(data?: IEmpiricalDistOperationParameters) { + super(data); + this._discriminator = "EmpiricalDistOperationParameters"; + } + + init(data?: any) { + super.init(data); + if (data) { + this.keepSamples = data["KeepSamples"]; + } + } + + static fromJS(data: any): EmpiricalDistOperationParameters { + data = typeof data === 'object' ? data : {}; + let result = new EmpiricalDistOperationParameters(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["KeepSamples"] = this.keepSamples; + super.toJSON(data); + return data; + } +} + +export interface IEmpiricalDistOperationParameters extends ITestDistOperationParameters { + keepSamples?: boolean | undefined; +} + +export class KSTestOperationParameters extends HypothesisTestParameters implements IKSTestOperationParameters { + + constructor(data?: IKSTestOperationParameters) { + super(data); + this._discriminator = "KSTestOperationParameters"; + } + + init(data?: any) { + super.init(data); + if (data) { + } + } + + static fromJS(data: any): KSTestOperationParameters { + data = typeof data === 'object' ? data : {}; + let result = new KSTestOperationParameters(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + super.toJSON(data); + return data; + } +} + +export interface IKSTestOperationParameters extends IHypothesisTestParameters { +} + +export abstract class ModelOperationParameters extends OperationParameters implements IModelOperationParameters { + + constructor(data?: IModelOperationParameters) { + super(data); + this._discriminator = "ModelOperationParameters"; + } + + init(data?: any) { + super.init(data); + if (data) { + } + } + + static fromJS(data: any): ModelOperationParameters { + data = typeof data === 'object' ? data : {}; + if (data["discriminator"] === "NewModelOperationParameters") { + let result = new NewModelOperationParameters(); + result.init(data); + return result; + } + if (data["discriminator"] === "AddComparisonParameters") { + let result = new AddComparisonParameters(); + result.init(data); + return result; + } + if (data["discriminator"] === "GetModelStateParameters") { + let result = new GetModelStateParameters(); + result.init(data); + return result; + } + throw new Error("The abstract class 'ModelOperationParameters' cannot be instantiated."); + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + super.toJSON(data); + return data; + } +} + +export interface IModelOperationParameters extends IOperationParameters { +} + +export class NewModelOperationParameters extends ModelOperationParameters implements INewModelOperationParameters { + riskControlTypes?: RiskControlType[] | undefined; + alpha?: number | undefined; + alphaInvestParameter?: AlphaInvestParameter | undefined; + + constructor(data?: INewModelOperationParameters) { + super(data); + this._discriminator = "NewModelOperationParameters"; + } + + init(data?: any) { + super.init(data); + if (data) { + if (data["RiskControlTypes"] && data["RiskControlTypes"].constructor === Array) { + this.riskControlTypes = []; + for (let item of data["RiskControlTypes"]) + this.riskControlTypes.push(item); + } + this.alpha = data["Alpha"]; + this.alphaInvestParameter = data["AlphaInvestParameter"] ? AlphaInvestParameter.fromJS(data["AlphaInvestParameter"]) : undefined; + } + } + + static fromJS(data: any): NewModelOperationParameters { + data = typeof data === 'object' ? data : {}; + let result = new NewModelOperationParameters(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + if (this.riskControlTypes && this.riskControlTypes.constructor === Array) { + data["RiskControlTypes"] = []; + for (let item of this.riskControlTypes) + data["RiskControlTypes"].push(item); + } + data["Alpha"] = this.alpha; + data["AlphaInvestParameter"] = this.alphaInvestParameter ? this.alphaInvestParameter.toJSON() : undefined; + super.toJSON(data); + return data; + } +} + +export interface INewModelOperationParameters extends IModelOperationParameters { + riskControlTypes?: RiskControlType[] | undefined; + alpha?: number | undefined; + alphaInvestParameter?: AlphaInvestParameter | undefined; +} + +export class AlphaInvestParameter extends UniqueJson implements IAlphaInvestParameter { + beta?: number | undefined; + gamma?: number | undefined; + delta?: number | undefined; + epsilon?: number | undefined; + windowSize?: number | undefined; + psi?: number | undefined; + + constructor(data?: IAlphaInvestParameter) { + super(data); + } + + init(data?: any) { + super.init(data); + if (data) { + this.beta = data["Beta"]; + this.gamma = data["Gamma"]; + this.delta = data["Delta"]; + this.epsilon = data["Epsilon"]; + this.windowSize = data["WindowSize"]; + this.psi = data["Psi"]; + } + } + + static fromJS(data: any): AlphaInvestParameter { + data = typeof data === 'object' ? data : {}; + let result = new AlphaInvestParameter(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["Beta"] = this.beta; + data["Gamma"] = this.gamma; + data["Delta"] = this.delta; + data["Epsilon"] = this.epsilon; + data["WindowSize"] = this.windowSize; + data["Psi"] = this.psi; + super.toJSON(data); + return data; + } +} + +export interface IAlphaInvestParameter extends IUniqueJson { + beta?: number | undefined; + gamma?: number | undefined; + delta?: number | undefined; + epsilon?: number | undefined; + windowSize?: number | undefined; + psi?: number | undefined; +} + +export class RootMeanSquareTestOperationParameters extends HypothesisTestParameters implements IRootMeanSquareTestOperationParameters { + seeded?: boolean | undefined; + pValueConvergenceThreshold?: number | undefined; + maxSimulationBatchCount?: number | undefined; + perBatchSimulationCount?: number | undefined; + + constructor(data?: IRootMeanSquareTestOperationParameters) { + super(data); + this._discriminator = "RootMeanSquareTestOperationParameters"; + } + + init(data?: any) { + super.init(data); + if (data) { + this.seeded = data["Seeded"]; + this.pValueConvergenceThreshold = data["PValueConvergenceThreshold"]; + this.maxSimulationBatchCount = data["MaxSimulationBatchCount"]; + this.perBatchSimulationCount = data["PerBatchSimulationCount"]; + } + } + + static fromJS(data: any): RootMeanSquareTestOperationParameters { + data = typeof data === 'object' ? data : {}; + let result = new RootMeanSquareTestOperationParameters(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["Seeded"] = this.seeded; + data["PValueConvergenceThreshold"] = this.pValueConvergenceThreshold; + data["MaxSimulationBatchCount"] = this.maxSimulationBatchCount; + data["PerBatchSimulationCount"] = this.perBatchSimulationCount; + super.toJSON(data); + return data; + } +} + +export interface IRootMeanSquareTestOperationParameters extends IHypothesisTestParameters { + seeded?: boolean | undefined; + pValueConvergenceThreshold?: number | undefined; + maxSimulationBatchCount?: number | undefined; + perBatchSimulationCount?: number | undefined; +} + +export class TTestOperationParameters extends HypothesisTestParameters implements ITTestOperationParameters { + + constructor(data?: ITTestOperationParameters) { + super(data); + this._discriminator = "TTestOperationParameters"; + } + + init(data?: any) { + super.init(data); + if (data) { + } + } + + static fromJS(data: any): TTestOperationParameters { + data = typeof data === 'object' ? data : {}; + let result = new TTestOperationParameters(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + super.toJSON(data); + return data; + } +} + +export interface ITTestOperationParameters extends IHypothesisTestParameters { +} + +export enum EffectSize { + Small = 1, + Meduim = 2, + Large = 4, +} + +export abstract class Result extends UniqueJson implements IResult { + progress?: number | undefined; + + protected _discriminator: string; + + constructor(data?: IResult) { + super(data); + this._discriminator = "Result"; + } + + init(data?: any) { + super.init(data); + if (data) { + this.progress = data["Progress"]; + } + } + + static fromJS(data: any): Result { + data = typeof data === 'object' ? data : {}; + if (data["discriminator"] === "ErrorResult") { + let result = new ErrorResult(); + result.init(data); + return result; + } + if (data["discriminator"] === "HistogramResult") { + let result = new HistogramResult(); + result.init(data); + return result; + } + if (data["discriminator"] === "DistResult") { + throw new Error("The abstract class 'DistResult' cannot be instantiated."); + } + if (data["discriminator"] === "ModelWealthResult") { + let result = new ModelWealthResult(); + result.init(data); + return result; + } + if (data["discriminator"] === "HypothesisTestResult") { + throw new Error("The abstract class 'HypothesisTestResult' cannot be instantiated."); + } + if (data["discriminator"] === "ModelOperationResult") { + throw new Error("The abstract class 'ModelOperationResult' cannot be instantiated."); + } + if (data["discriminator"] === "RecommenderResult") { + let result = new RecommenderResult(); + result.init(data); + return result; + } + if (data["discriminator"] === "Decision") { + let result = new Decision(); + result.init(data); + return result; + } + if (data["discriminator"] === "OptimizerResult") { + let result = new OptimizerResult(); + result.init(data); + return result; + } + if (data["discriminator"] === "ExampleResult") { + let result = new ExampleResult(); + result.init(data); + return result; + } + if (data["discriminator"] === "NewModelOperationResult") { + let result = new NewModelOperationResult(); + result.init(data); + return result; + } + if (data["discriminator"] === "AddComparisonResult") { + let result = new AddComparisonResult(); + result.init(data); + return result; + } + if (data["discriminator"] === "GetModelStateResult") { + let result = new GetModelStateResult(); + result.init(data); + return result; + } + if (data["discriminator"] === "FeatureImportanceResult") { + let result = new FeatureImportanceResult(); + result.init(data); + return result; + } + if (data["discriminator"] === "RawDataResult") { + let result = new RawDataResult(); + result.init(data); + return result; + } + if (data["discriminator"] === "SampleResult") { + let result = new SampleResult(); + result.init(data); + return result; + } + if (data["discriminator"] === "CDFResult") { + let result = new CDFResult(); + result.init(data); + return result; + } + if (data["discriminator"] === "ChiSquaredTestResult") { + let result = new ChiSquaredTestResult(); + result.init(data); + return result; + } + if (data["discriminator"] === "CorrelationTestResult") { + let result = new CorrelationTestResult(); + result.init(data); + return result; + } + if (data["discriminator"] === "EmpiricalDistResult") { + let result = new EmpiricalDistResult(); + result.init(data); + return result; + } + if (data["discriminator"] === "KSTestResult") { + let result = new KSTestResult(); + result.init(data); + return result; + } + if (data["discriminator"] === "RootMeanSquareTestResult") { + let result = new RootMeanSquareTestResult(); + result.init(data); + return result; + } + if (data["discriminator"] === "TTestResult") { + let result = new TTestResult(); + result.init(data); + return result; + } + if (data["discriminator"] === "FrequentItemsetResult") { + let result = new FrequentItemsetResult(); + result.init(data); + return result; + } + throw new Error("The abstract class 'Result' cannot be instantiated."); + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["discriminator"] = this._discriminator; + data["Progress"] = this.progress; + super.toJSON(data); + return data; + } +} + +export interface IResult extends IUniqueJson { + progress?: number | undefined; +} + +export class ErrorResult extends Result implements IErrorResult { + message?: string | undefined; + + constructor(data?: IErrorResult) { + super(data); + this._discriminator = "ErrorResult"; + } + + init(data?: any) { + super.init(data); + if (data) { + this.message = data["Message"]; + } + } + + static fromJS(data: any): ErrorResult { + data = typeof data === 'object' ? data : {}; + let result = new ErrorResult(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["Message"] = this.message; + super.toJSON(data); + return data; + } +} + +export interface IErrorResult extends IResult { + message?: string | undefined; +} + +export abstract class DistResult extends Result implements IDistResult { + sampleSize?: number | undefined; + populationSize?: number | undefined; + + constructor(data?: IDistResult) { + super(data); + this._discriminator = "DistResult"; + } + + init(data?: any) { + super.init(data); + if (data) { + this.sampleSize = data["SampleSize"]; + this.populationSize = data["PopulationSize"]; + } + } + + static fromJS(data: any): DistResult { + data = typeof data === 'object' ? data : {}; + if (data["discriminator"] === "HistogramResult") { + let result = new HistogramResult(); + result.init(data); + return result; + } + if (data["discriminator"] === "RawDataResult") { + let result = new RawDataResult(); + result.init(data); + return result; + } + if (data["discriminator"] === "SampleResult") { + let result = new SampleResult(); + result.init(data); + return result; + } + if (data["discriminator"] === "CDFResult") { + let result = new CDFResult(); + result.init(data); + return result; + } + if (data["discriminator"] === "EmpiricalDistResult") { + let result = new EmpiricalDistResult(); + result.init(data); + return result; + } + throw new Error("The abstract class 'DistResult' cannot be instantiated."); + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["SampleSize"] = this.sampleSize; + data["PopulationSize"] = this.populationSize; + super.toJSON(data); + return data; + } +} + +export interface IDistResult extends IResult { + sampleSize?: number | undefined; + populationSize?: number | undefined; +} + +export class HistogramResult extends DistResult implements IHistogramResult { + aggregateResults?: AggregateResult[][] | undefined; + isEmpty?: boolean | undefined; + brushes?: Brush[] | undefined; + binRanges?: BinRange[] | undefined; + aggregateParameters?: AggregateParameters[] | undefined; + nullValueCount?: number | undefined; + bins?: { [key: string]: Bin; } | undefined; + + constructor(data?: IHistogramResult) { + super(data); + this._discriminator = "HistogramResult"; + } + + init(data?: any) { + super.init(data); + if (data) { + if (data["AggregateResults"] && data["AggregateResults"].constructor === Array) { + this.aggregateResults = []; + for (let item of data["AggregateResults"]) + this.aggregateResults.push(item); + } + this.isEmpty = data["IsEmpty"]; + if (data["Brushes"] && data["Brushes"].constructor === Array) { + this.brushes = []; + for (let item of data["Brushes"]) + this.brushes.push(Brush.fromJS(item)); + } + if (data["BinRanges"] && data["BinRanges"].constructor === Array) { + this.binRanges = []; + for (let item of data["BinRanges"]) + this.binRanges.push(BinRange.fromJS(item)); + } + if (data["AggregateParameters"] && data["AggregateParameters"].constructor === Array) { + this.aggregateParameters = []; + for (let item of data["AggregateParameters"]) + this.aggregateParameters.push(AggregateParameters.fromJS(item)); + } + this.nullValueCount = data["NullValueCount"]; + if (data["Bins"]) { + this.bins = {}; + for (let key in data["Bins"]) { + if (data["Bins"].hasOwnProperty(key)) + this.bins[key] = data["Bins"][key] ? Bin.fromJS(data["Bins"][key]) : new Bin(); + } + } + } + } + + static fromJS(data: any): HistogramResult { + data = typeof data === 'object' ? data : {}; + let result = new HistogramResult(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + if (this.aggregateResults && this.aggregateResults.constructor === Array) { + data["AggregateResults"] = []; + for (let item of this.aggregateResults) + data["AggregateResults"].push(item); + } + data["IsEmpty"] = this.isEmpty; + if (this.brushes && this.brushes.constructor === Array) { + data["Brushes"] = []; + for (let item of this.brushes) + data["Brushes"].push(item.toJSON()); + } + if (this.binRanges && this.binRanges.constructor === Array) { + data["BinRanges"] = []; + for (let item of this.binRanges) + data["BinRanges"].push(item.toJSON()); + } + if (this.aggregateParameters && this.aggregateParameters.constructor === Array) { + data["AggregateParameters"] = []; + for (let item of this.aggregateParameters) + data["AggregateParameters"].push(item.toJSON()); + } + data["NullValueCount"] = this.nullValueCount; + if (this.bins) { + data["Bins"] = {}; + for (let key in this.bins) { + if (this.bins.hasOwnProperty(key)) + data["Bins"][key] = this.bins[key]; + } + } + super.toJSON(data); + return data; + } +} + +export interface IHistogramResult extends IDistResult { + aggregateResults?: AggregateResult[][] | undefined; + isEmpty?: boolean | undefined; + brushes?: Brush[] | undefined; + binRanges?: BinRange[] | undefined; + aggregateParameters?: AggregateParameters[] | undefined; + nullValueCount?: number | undefined; + bins?: { [key: string]: Bin; } | undefined; +} + +export abstract class AggregateResult implements IAggregateResult { + hasResult?: boolean | undefined; + n?: number | undefined; + + protected _discriminator: string; + + constructor(data?: IAggregateResult) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + this._discriminator = "AggregateResult"; + } + + init(data?: any) { + if (data) { + this.hasResult = data["HasResult"]; + this.n = data["N"]; + } + } + + static fromJS(data: any): AggregateResult | undefined { + if (data === null || data === undefined) { + return undefined; + } + data = typeof data === 'object' ? data : {}; + if (data["discriminator"] === "MarginAggregateResult") { + let result = new MarginAggregateResult(); + result.init(data); + return result; + } + if (data["discriminator"] === "DoubleValueAggregateResult") { + let result = new DoubleValueAggregateResult(); + result.init(data); + return result; + } + if (data["discriminator"] === "PointsAggregateResult") { + let result = new PointsAggregateResult(); + result.init(data); + return result; + } + if (data["discriminator"] === "SumEstimationAggregateResult") { + let result = new SumEstimationAggregateResult(); + result.init(data); + return result; + } + throw new Error("The abstract class 'AggregateResult' cannot be instantiated."); + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["discriminator"] = this._discriminator; + data["HasResult"] = this.hasResult; + data["N"] = this.n; + return data; + } +} + +export interface IAggregateResult { + hasResult?: boolean | undefined; + n?: number | undefined; +} + +export class MarginAggregateResult extends AggregateResult implements IMarginAggregateResult { + margin?: number | undefined; + absolutMargin?: number | undefined; + sumOfSquare?: number | undefined; + sampleStandardDeviation?: number | undefined; + mean?: number | undefined; + ex?: number | undefined; + ex2?: number | undefined; + variance?: number | undefined; + + constructor(data?: IMarginAggregateResult) { + super(data); + this._discriminator = "MarginAggregateResult"; + } + + init(data?: any) { + super.init(data); + if (data) { + this.margin = data["Margin"]; + this.absolutMargin = data["AbsolutMargin"]; + this.sumOfSquare = data["SumOfSquare"]; + this.sampleStandardDeviation = data["SampleStandardDeviation"]; + this.mean = data["Mean"]; + this.ex = data["Ex"]; + this.ex2 = data["Ex2"]; + this.variance = data["Variance"]; + } + } + + static fromJS(data: any): MarginAggregateResult { + data = typeof data === 'object' ? data : {}; + let result = new MarginAggregateResult(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["Margin"] = this.margin; + data["AbsolutMargin"] = this.absolutMargin; + data["SumOfSquare"] = this.sumOfSquare; + data["SampleStandardDeviation"] = this.sampleStandardDeviation; + data["Mean"] = this.mean; + data["Ex"] = this.ex; + data["Ex2"] = this.ex2; + data["Variance"] = this.variance; + super.toJSON(data); + return data; + } +} + +export interface IMarginAggregateResult extends IAggregateResult { + margin?: number | undefined; + absolutMargin?: number | undefined; + sumOfSquare?: number | undefined; + sampleStandardDeviation?: number | undefined; + mean?: number | undefined; + ex?: number | undefined; + ex2?: number | undefined; + variance?: number | undefined; +} + +export class DoubleValueAggregateResult extends AggregateResult implements IDoubleValueAggregateResult { + result?: number | undefined; + temporaryResult?: number | undefined; + + constructor(data?: IDoubleValueAggregateResult) { + super(data); + this._discriminator = "DoubleValueAggregateResult"; + } + + init(data?: any) { + super.init(data); + if (data) { + this.result = data["Result"]; + this.temporaryResult = data["TemporaryResult"]; + } + } + + static fromJS(data: any): DoubleValueAggregateResult { + data = typeof data === 'object' ? data : {}; + if (data["discriminator"] === "SumEstimationAggregateResult") { + let result = new SumEstimationAggregateResult(); + result.init(data); + return result; + } + let result = new DoubleValueAggregateResult(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["Result"] = this.result; + data["TemporaryResult"] = this.temporaryResult; + super.toJSON(data); + return data; + } +} + +export interface IDoubleValueAggregateResult extends IAggregateResult { + result?: number | undefined; + temporaryResult?: number | undefined; +} + +export class PointsAggregateResult extends AggregateResult implements IPointsAggregateResult { + points?: Point[] | undefined; + + constructor(data?: IPointsAggregateResult) { + super(data); + this._discriminator = "PointsAggregateResult"; + } + + init(data?: any) { + super.init(data); + if (data) { + if (data["Points"] && data["Points"].constructor === Array) { + this.points = []; + for (let item of data["Points"]) + this.points.push(Point.fromJS(item)); + } + } + } + + static fromJS(data: any): PointsAggregateResult { + data = typeof data === 'object' ? data : {}; + let result = new PointsAggregateResult(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + if (this.points && this.points.constructor === Array) { + data["Points"] = []; + for (let item of this.points) + data["Points"].push(item.toJSON()); + } + super.toJSON(data); + return data; + } +} + +export interface IPointsAggregateResult extends IAggregateResult { + points?: Point[] | undefined; +} + +export class Point implements IPoint { + x?: number | undefined; + y?: number | undefined; + + constructor(data?: IPoint) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(data?: any) { + if (data) { + this.x = data["X"]; + this.y = data["Y"]; + } + } + + static fromJS(data: any): Point { + data = typeof data === 'object' ? data : {}; + let result = new Point(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["X"] = this.x; + data["Y"] = this.y; + return data; + } +} + +export interface IPoint { + x?: number | undefined; + y?: number | undefined; +} + +export class SumEstimationAggregateResult extends DoubleValueAggregateResult implements ISumEstimationAggregateResult { + sum?: number | undefined; + sumEstimation?: number | undefined; + + constructor(data?: ISumEstimationAggregateResult) { + super(data); + this._discriminator = "SumEstimationAggregateResult"; + } + + init(data?: any) { + super.init(data); + if (data) { + this.sum = data["Sum"]; + this.sumEstimation = data["SumEstimation"]; + } + } + + static fromJS(data: any): SumEstimationAggregateResult { + data = typeof data === 'object' ? data : {}; + let result = new SumEstimationAggregateResult(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["Sum"] = this.sum; + data["SumEstimation"] = this.sumEstimation; + super.toJSON(data); + return data; + } +} + +export interface ISumEstimationAggregateResult extends IDoubleValueAggregateResult { + sum?: number | undefined; + sumEstimation?: number | undefined; +} + +export class Brush implements IBrush { + brushIndex?: number | undefined; + brushEnum?: BrushEnum | undefined; + + constructor(data?: IBrush) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(data?: any) { + if (data) { + this.brushIndex = data["BrushIndex"]; + this.brushEnum = data["BrushEnum"]; + } + } + + static fromJS(data: any): Brush { + data = typeof data === 'object' ? data : {}; + let result = new Brush(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["BrushIndex"] = this.brushIndex; + data["BrushEnum"] = this.brushEnum; + return data; + } +} + +export interface IBrush { + brushIndex?: number | undefined; + brushEnum?: BrushEnum | undefined; +} + +export enum BrushEnum { + Overlap = 0, + Rest = 1, + All = 2, + UserSpecified = 3, +} + +export abstract class BinRange implements IBinRange { + minValue?: number | undefined; + maxValue?: number | undefined; + targetBinNumber?: number | undefined; + + protected _discriminator: string; + + constructor(data?: IBinRange) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + this._discriminator = "BinRange"; + } + + init(data?: any) { + if (data) { + this.minValue = data["MinValue"]; + this.maxValue = data["MaxValue"]; + this.targetBinNumber = data["TargetBinNumber"]; + } + } + + static fromJS(data: any): BinRange { + data = typeof data === 'object' ? data : {}; + if (data["discriminator"] === "NominalBinRange") { + let result = new NominalBinRange(); + result.init(data); + return result; + } + if (data["discriminator"] === "QuantitativeBinRange") { + let result = new QuantitativeBinRange(); + result.init(data); + return result; + } + if (data["discriminator"] === "AggregateBinRange") { + let result = new AggregateBinRange(); + result.init(data); + return result; + } + if (data["discriminator"] === "AlphabeticBinRange") { + let result = new AlphabeticBinRange(); + result.init(data); + return result; + } + if (data["discriminator"] === "DateTimeBinRange") { + let result = new DateTimeBinRange(); + result.init(data); + return result; + } + throw new Error("The abstract class 'BinRange' cannot be instantiated."); + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["discriminator"] = this._discriminator; + data["MinValue"] = this.minValue; + data["MaxValue"] = this.maxValue; + data["TargetBinNumber"] = this.targetBinNumber; + return data; + } +} + +export interface IBinRange { + minValue?: number | undefined; + maxValue?: number | undefined; + targetBinNumber?: number | undefined; +} + +export class NominalBinRange extends BinRange implements INominalBinRange { + labelsValue?: { [key: string]: number; } | undefined; + valuesLabel?: { [key: string]: string; } | undefined; + + constructor(data?: INominalBinRange) { + super(data); + this._discriminator = "NominalBinRange"; + } + + init(data?: any) { + super.init(data); + if (data) { + if (data["LabelsValue"]) { + this.labelsValue = {}; + for (let key in data["LabelsValue"]) { + if (data["LabelsValue"].hasOwnProperty(key)) + this.labelsValue[key] = data["LabelsValue"][key]; + } + } + if (data["ValuesLabel"]) { + this.valuesLabel = {}; + for (let key in data["ValuesLabel"]) { + if (data["ValuesLabel"].hasOwnProperty(key)) + this.valuesLabel[key] = data["ValuesLabel"][key]; + } + } + } + } + + static fromJS(data: any): NominalBinRange { + data = typeof data === 'object' ? data : {}; + let result = new NominalBinRange(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + if (this.labelsValue) { + data["LabelsValue"] = {}; + for (let key in this.labelsValue) { + if (this.labelsValue.hasOwnProperty(key)) + data["LabelsValue"][key] = this.labelsValue[key]; + } + } + if (this.valuesLabel) { + data["ValuesLabel"] = {}; + for (let key in this.valuesLabel) { + if (this.valuesLabel.hasOwnProperty(key)) + data["ValuesLabel"][key] = this.valuesLabel[key]; + } + } + super.toJSON(data); + return data; + } +} + +export interface INominalBinRange extends IBinRange { + labelsValue?: { [key: string]: number; } | undefined; + valuesLabel?: { [key: string]: string; } | undefined; +} + +export class QuantitativeBinRange extends BinRange implements IQuantitativeBinRange { + isIntegerRange?: boolean | undefined; + step?: number | undefined; + + constructor(data?: IQuantitativeBinRange) { + super(data); + this._discriminator = "QuantitativeBinRange"; + } + + init(data?: any) { + super.init(data); + if (data) { + this.isIntegerRange = data["IsIntegerRange"]; + this.step = data["Step"]; + } + } + + static fromJS(data: any): QuantitativeBinRange { + data = typeof data === 'object' ? data : {}; + let result = new QuantitativeBinRange(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["IsIntegerRange"] = this.isIntegerRange; + data["Step"] = this.step; + super.toJSON(data); + return data; + } +} + +export interface IQuantitativeBinRange extends IBinRange { + isIntegerRange?: boolean | undefined; + step?: number | undefined; +} + +export class AggregateBinRange extends BinRange implements IAggregateBinRange { + + constructor(data?: IAggregateBinRange) { + super(data); + this._discriminator = "AggregateBinRange"; + } + + init(data?: any) { + super.init(data); + if (data) { + } + } + + static fromJS(data: any): AggregateBinRange { + data = typeof data === 'object' ? data : {}; + let result = new AggregateBinRange(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + super.toJSON(data); + return data; + } +} + +export interface IAggregateBinRange extends IBinRange { +} + +export class AlphabeticBinRange extends BinRange implements IAlphabeticBinRange { + prefix?: string | undefined; + labelsValue?: { [key: string]: number; } | undefined; + valuesLabel?: { [key: string]: string; } | undefined; + + constructor(data?: IAlphabeticBinRange) { + super(data); + this._discriminator = "AlphabeticBinRange"; + } + + init(data?: any) { + super.init(data); + if (data) { + this.prefix = data["Prefix"]; + if (data["LabelsValue"]) { + this.labelsValue = {}; + for (let key in data["LabelsValue"]) { + if (data["LabelsValue"].hasOwnProperty(key)) + this.labelsValue[key] = data["LabelsValue"][key]; + } + } + if (data["ValuesLabel"]) { + this.valuesLabel = {}; + for (let key in data["ValuesLabel"]) { + if (data["ValuesLabel"].hasOwnProperty(key)) + this.valuesLabel[key] = data["ValuesLabel"][key]; + } + } + } + } + + static fromJS(data: any): AlphabeticBinRange { + data = typeof data === 'object' ? data : {}; + let result = new AlphabeticBinRange(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["Prefix"] = this.prefix; + if (this.labelsValue) { + data["LabelsValue"] = {}; + for (let key in this.labelsValue) { + if (this.labelsValue.hasOwnProperty(key)) + data["LabelsValue"][key] = this.labelsValue[key]; + } + } + if (this.valuesLabel) { + data["ValuesLabel"] = {}; + for (let key in this.valuesLabel) { + if (this.valuesLabel.hasOwnProperty(key)) + data["ValuesLabel"][key] = this.valuesLabel[key]; + } + } + super.toJSON(data); + return data; + } +} + +export interface IAlphabeticBinRange extends IBinRange { + prefix?: string | undefined; + labelsValue?: { [key: string]: number; } | undefined; + valuesLabel?: { [key: string]: string; } | undefined; +} + +export class DateTimeBinRange extends BinRange implements IDateTimeBinRange { + step?: DateTimeStep | undefined; + + constructor(data?: IDateTimeBinRange) { + super(data); + this._discriminator = "DateTimeBinRange"; + } + + init(data?: any) { + super.init(data); + if (data) { + this.step = data["Step"] ? DateTimeStep.fromJS(data["Step"]) : undefined; + } + } + + static fromJS(data: any): DateTimeBinRange { + data = typeof data === 'object' ? data : {}; + let result = new DateTimeBinRange(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["Step"] = this.step ? this.step.toJSON() : undefined; + super.toJSON(data); + return data; + } +} + +export interface IDateTimeBinRange extends IBinRange { + step?: DateTimeStep | undefined; +} + +export class DateTimeStep implements IDateTimeStep { + dateTimeStepGranularity?: DateTimeStepGranularity | undefined; + dateTimeStepValue?: number | undefined; + dateTimeStepMaxValue?: number | undefined; + + constructor(data?: IDateTimeStep) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(data?: any) { + if (data) { + this.dateTimeStepGranularity = data["DateTimeStepGranularity"]; + this.dateTimeStepValue = data["DateTimeStepValue"]; + this.dateTimeStepMaxValue = data["DateTimeStepMaxValue"]; + } + } + + static fromJS(data: any): DateTimeStep { + data = typeof data === 'object' ? data : {}; + let result = new DateTimeStep(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["DateTimeStepGranularity"] = this.dateTimeStepGranularity; + data["DateTimeStepValue"] = this.dateTimeStepValue; + data["DateTimeStepMaxValue"] = this.dateTimeStepMaxValue; + return data; + } +} + +export interface IDateTimeStep { + dateTimeStepGranularity?: DateTimeStepGranularity | undefined; + dateTimeStepValue?: number | undefined; + dateTimeStepMaxValue?: number | undefined; +} + +export enum DateTimeStepGranularity { + Second = 0, + Minute = 1, + Hour = 2, + Day = 3, + Month = 4, + Year = 5, +} + +export class Bin implements IBin { + aggregateResults?: AggregateResult[] | undefined; + count?: number | undefined; + binIndex?: BinIndex | undefined; + spans?: Span[] | undefined; + xSize?: number | undefined; + ySize?: number | undefined; + + constructor(data?: IBin) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(data?: any) { + if (data) { + if (data["AggregateResults"] && data["AggregateResults"].constructor === Array) { + this.aggregateResults = []; + for (let item of data["AggregateResults"]) { + let fromJs = AggregateResult.fromJS(item); + if (fromJs) + this.aggregateResults.push(fromJs); + } + } + this.count = data["Count"]; + this.binIndex = data["BinIndex"] ? BinIndex.fromJS(data["BinIndex"]) : undefined; + if (data["Spans"] && data["Spans"].constructor === Array) { + this.spans = []; + for (let item of data["Spans"]) + this.spans.push(Span.fromJS(item)); + } + this.xSize = data["XSize"]; + this.ySize = data["YSize"]; + } + } + + static fromJS(data: any): Bin { + data = typeof data === 'object' ? data : {}; + let result = new Bin(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + if (this.aggregateResults && this.aggregateResults.constructor === Array) { + data["AggregateResults"] = []; + for (let item of this.aggregateResults) + data["AggregateResults"].push(item.toJSON()); + } + data["Count"] = this.count; + data["BinIndex"] = this.binIndex ? this.binIndex.toJSON() : undefined; + if (this.spans && this.spans.constructor === Array) { + data["Spans"] = []; + for (let item of this.spans) + data["Spans"].push(item.toJSON()); + } + data["XSize"] = this.xSize; + data["YSize"] = this.ySize; + return data; + } +} + +export interface IBin { + aggregateResults?: AggregateResult[] | undefined; + count?: number | undefined; + binIndex?: BinIndex | undefined; + spans?: Span[] | undefined; + xSize?: number | undefined; + ySize?: number | undefined; +} + +export class BinIndex implements IBinIndex { + indices?: number[] | undefined; + flatIndex?: number | undefined; + + constructor(data?: IBinIndex) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(data?: any) { + if (data) { + if (data["Indices"] && data["Indices"].constructor === Array) { + this.indices = []; + for (let item of data["Indices"]) + this.indices.push(item); + } + this.flatIndex = data["FlatIndex"]; + } + } + + static fromJS(data: any): BinIndex { + data = typeof data === 'object' ? data : {}; + let result = new BinIndex(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + if (this.indices && this.indices.constructor === Array) { + data["Indices"] = []; + for (let item of this.indices) + data["Indices"].push(item); + } + data["FlatIndex"] = this.flatIndex; + return data; + } +} + +export interface IBinIndex { + indices?: number[] | undefined; + flatIndex?: number | undefined; +} + +export class Span implements ISpan { + min?: number | undefined; + max?: number | undefined; + index?: number | undefined; + + constructor(data?: ISpan) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(data?: any) { + if (data) { + this.min = data["Min"]; + this.max = data["Max"]; + this.index = data["Index"]; + } + } + + static fromJS(data: any): Span { + data = typeof data === 'object' ? data : {}; + let result = new Span(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["Min"] = this.min; + data["Max"] = this.max; + data["Index"] = this.index; + return data; + } +} + +export interface ISpan { + min?: number | undefined; + max?: number | undefined; + index?: number | undefined; +} + +export class ModelWealthResult extends Result implements IModelWealthResult { + wealth?: number | undefined; + startWealth?: number | undefined; + + constructor(data?: IModelWealthResult) { + super(data); + this._discriminator = "ModelWealthResult"; + } + + init(data?: any) { + super.init(data); + if (data) { + this.wealth = data["Wealth"]; + this.startWealth = data["StartWealth"]; + } + } + + static fromJS(data: any): ModelWealthResult { + data = typeof data === 'object' ? data : {}; + let result = new ModelWealthResult(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["Wealth"] = this.wealth; + data["StartWealth"] = this.startWealth; + super.toJSON(data); + return data; + } +} + +export interface IModelWealthResult extends IResult { + wealth?: number | undefined; + startWealth?: number | undefined; +} + +export abstract class HypothesisTestResult extends Result implements IHypothesisTestResult { + pValue?: number | undefined; + statistic?: number | undefined; + support?: number | undefined; + sampleSizes?: number[] | undefined; + errorMessage?: string | undefined; + + constructor(data?: IHypothesisTestResult) { + super(data); + this._discriminator = "HypothesisTestResult"; + } + + init(data?: any) { + super.init(data); + if (data) { + this.pValue = data["PValue"]; + this.statistic = data["Statistic"]; + this.support = data["Support"]; + if (data["SampleSizes"] && data["SampleSizes"].constructor === Array) { + this.sampleSizes = []; + for (let item of data["SampleSizes"]) + this.sampleSizes.push(item); + } + this.errorMessage = data["ErrorMessage"]; + } + } + + static fromJS(data: any): HypothesisTestResult { + data = typeof data === 'object' ? data : {}; + if (data["discriminator"] === "ChiSquaredTestResult") { + let result = new ChiSquaredTestResult(); + result.init(data); + return result; + } + if (data["discriminator"] === "CorrelationTestResult") { + let result = new CorrelationTestResult(); + result.init(data); + return result; + } + if (data["discriminator"] === "KSTestResult") { + let result = new KSTestResult(); + result.init(data); + return result; + } + if (data["discriminator"] === "RootMeanSquareTestResult") { + let result = new RootMeanSquareTestResult(); + result.init(data); + return result; + } + if (data["discriminator"] === "TTestResult") { + let result = new TTestResult(); + result.init(data); + return result; + } + throw new Error("The abstract class 'HypothesisTestResult' cannot be instantiated."); + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["PValue"] = this.pValue; + data["Statistic"] = this.statistic; + data["Support"] = this.support; + if (this.sampleSizes && this.sampleSizes.constructor === Array) { + data["SampleSizes"] = []; + for (let item of this.sampleSizes) + data["SampleSizes"].push(item); + } + data["ErrorMessage"] = this.errorMessage; + super.toJSON(data); + return data; + } +} + +export interface IHypothesisTestResult extends IResult { + pValue?: number | undefined; + statistic?: number | undefined; + support?: number | undefined; + sampleSizes?: number[] | undefined; + errorMessage?: string | undefined; +} + +export abstract class ModelOperationResult extends Result implements IModelOperationResult { + modelId?: ModelId | undefined; + + constructor(data?: IModelOperationResult) { + super(data); + this._discriminator = "ModelOperationResult"; + } + + init(data?: any) { + super.init(data); + if (data) { + this.modelId = data["ModelId"] ? ModelId.fromJS(data["ModelId"]) : undefined; + } + } + + static fromJS(data: any): ModelOperationResult { + data = typeof data === 'object' ? data : {}; + if (data["discriminator"] === "NewModelOperationResult") { + let result = new NewModelOperationResult(); + result.init(data); + return result; + } + if (data["discriminator"] === "AddComparisonResult") { + let result = new AddComparisonResult(); + result.init(data); + return result; + } + if (data["discriminator"] === "GetModelStateResult") { + let result = new GetModelStateResult(); + result.init(data); + return result; + } + throw new Error("The abstract class 'ModelOperationResult' cannot be instantiated."); + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["ModelId"] = this.modelId ? this.modelId.toJSON() : undefined; + super.toJSON(data); + return data; + } +} + +export interface IModelOperationResult extends IResult { + modelId?: ModelId | undefined; +} + +export class RecommenderResult extends Result implements IRecommenderResult { + recommendedHistograms?: RecommendedHistogram[] | undefined; + totalCount?: number | undefined; + + constructor(data?: IRecommenderResult) { + super(data); + this._discriminator = "RecommenderResult"; + } + + init(data?: any) { + super.init(data); + if (data) { + if (data["RecommendedHistograms"] && data["RecommendedHistograms"].constructor === Array) { + this.recommendedHistograms = []; + for (let item of data["RecommendedHistograms"]) + this.recommendedHistograms.push(RecommendedHistogram.fromJS(item)); + } + this.totalCount = data["TotalCount"]; + } + } + + static fromJS(data: any): RecommenderResult { + data = typeof data === 'object' ? data : {}; + let result = new RecommenderResult(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + if (this.recommendedHistograms && this.recommendedHistograms.constructor === Array) { + data["RecommendedHistograms"] = []; + for (let item of this.recommendedHistograms) + data["RecommendedHistograms"].push(item.toJSON()); + } + data["TotalCount"] = this.totalCount; + super.toJSON(data); + return data; + } +} + +export interface IRecommenderResult extends IResult { + recommendedHistograms?: RecommendedHistogram[] | undefined; + totalCount?: number | undefined; +} + +export class RecommendedHistogram implements IRecommendedHistogram { + histogramResult?: HistogramResult | undefined; + selectedBinIndices?: BinIndex[] | undefined; + selections?: Selection[] | undefined; + pValue?: number | undefined; + significance?: boolean | undefined; + decision?: Decision | undefined; + effectSize?: number | undefined; + hypothesisTestResult?: HypothesisTestResult | undefined; + id?: string | undefined; + xAttribute?: Attribute | undefined; + yAttribute?: Attribute | undefined; + + constructor(data?: IRecommendedHistogram) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(data?: any) { + if (data) { + this.histogramResult = data["HistogramResult"] ? HistogramResult.fromJS(data["HistogramResult"]) : undefined; + if (data["SelectedBinIndices"] && data["SelectedBinIndices"].constructor === Array) { + this.selectedBinIndices = []; + for (let item of data["SelectedBinIndices"]) + this.selectedBinIndices.push(BinIndex.fromJS(item)); + } + if (data["Selections"] && data["Selections"].constructor === Array) { + this.selections = []; + for (let item of data["Selections"]) + this.selections.push(Selection.fromJS(item)); + } + this.pValue = data["PValue"]; + this.significance = data["Significance"]; + this.decision = data["Decision"] ? Decision.fromJS(data["Decision"]) : undefined; + this.effectSize = data["EffectSize"]; + this.hypothesisTestResult = data["HypothesisTestResult"] ? HypothesisTestResult.fromJS(data["HypothesisTestResult"]) : undefined; + this.id = data["Id"]; + this.xAttribute = data["XAttribute"] ? Attribute.fromJS(data["XAttribute"]) : undefined; + this.yAttribute = data["YAttribute"] ? Attribute.fromJS(data["YAttribute"]) : undefined; + } + } + + static fromJS(data: any): RecommendedHistogram { + data = typeof data === 'object' ? data : {}; + let result = new RecommendedHistogram(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["HistogramResult"] = this.histogramResult ? this.histogramResult.toJSON() : undefined; + if (this.selectedBinIndices && this.selectedBinIndices.constructor === Array) { + data["SelectedBinIndices"] = []; + for (let item of this.selectedBinIndices) + data["SelectedBinIndices"].push(item.toJSON()); + } + if (this.selections && this.selections.constructor === Array) { + data["Selections"] = []; + for (let item of this.selections) + data["Selections"].push(item.toJSON()); + } + data["PValue"] = this.pValue; + data["Significance"] = this.significance; + data["Decision"] = this.decision ? this.decision.toJSON() : undefined; + data["EffectSize"] = this.effectSize; + data["HypothesisTestResult"] = this.hypothesisTestResult ? this.hypothesisTestResult.toJSON() : undefined; + data["Id"] = this.id; + data["XAttribute"] = this.xAttribute ? this.xAttribute.toJSON() : undefined; + data["YAttribute"] = this.yAttribute ? this.yAttribute.toJSON() : undefined; + return data; + } +} + +export interface IRecommendedHistogram { + histogramResult?: HistogramResult | undefined; + selectedBinIndices?: BinIndex[] | undefined; + selections?: Selection[] | undefined; + pValue?: number | undefined; + significance?: boolean | undefined; + decision?: Decision | undefined; + effectSize?: number | undefined; + hypothesisTestResult?: HypothesisTestResult | undefined; + id?: string | undefined; + xAttribute?: Attribute | undefined; + yAttribute?: Attribute | undefined; +} + +export class Selection implements ISelection { + statements?: Statement[] | undefined; + filterHistogramOperationReference?: IOperationReference | undefined; + + constructor(data?: ISelection) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(data?: any) { + if (data) { + if (data["Statements"] && data["Statements"].constructor === Array) { + this.statements = []; + for (let item of data["Statements"]) + this.statements.push(Statement.fromJS(item)); + } + this.filterHistogramOperationReference = data["FilterHistogramOperationReference"] ? IOperationReference.fromJS(data["FilterHistogramOperationReference"]) : undefined; + } + } + + static fromJS(data: any): Selection { + data = typeof data === 'object' ? data : {}; + let result = new Selection(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + if (this.statements && this.statements.constructor === Array) { + data["Statements"] = []; + for (let item of this.statements) + data["Statements"].push(item.toJSON()); + } + data["FilterHistogramOperationReference"] = this.filterHistogramOperationReference ? this.filterHistogramOperationReference.toJSON() : undefined; + return data; + } +} + +export interface ISelection { + statements?: Statement[] | undefined; + filterHistogramOperationReference?: IOperationReference | undefined; +} + +export class Statement implements IStatement { + attribute?: Attribute | undefined; + predicate?: Predicate | undefined; + value?: any | undefined; + + constructor(data?: IStatement) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(data?: any) { + if (data) { + this.attribute = data["Attribute"] ? Attribute.fromJS(data["Attribute"]) : undefined; + this.predicate = data["Predicate"]; + this.value = data["Value"]; + } + } + + static fromJS(data: any): Statement { + data = typeof data === 'object' ? data : {}; + let result = new Statement(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["Attribute"] = this.attribute ? this.attribute.toJSON() : undefined; + data["Predicate"] = this.predicate; + data["Value"] = this.value; + return data; + } +} + +export interface IStatement { + attribute?: Attribute | undefined; + predicate?: Predicate | undefined; + value?: any | undefined; +} + +export enum Predicate { + EQUALS = 0, + LIKE = 1, + GREATER_THAN = 2, + LESS_THAN = 3, + GREATER_THAN_EQUAL = 4, + LESS_THAN_EQUAL = 5, + STARTS_WITH = 6, + ENDS_WITH = 7, + CONTAINS = 8, +} + +export abstract class IOperationReference implements IIOperationReference { + id?: string | undefined; + + protected _discriminator: string; + + constructor(data?: IIOperationReference) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + this._discriminator = "IOperationReference"; + } + + init(data?: any) { + if (data) { + this.id = data["Id"]; + } + } + + static fromJS(data: any): IOperationReference { + data = typeof data === 'object' ? data : {}; + if (data["discriminator"] === "OperationReference") { + let result = new OperationReference(); + result.init(data); + return result; + } + throw new Error("The abstract class 'IOperationReference' cannot be instantiated."); + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["discriminator"] = this._discriminator; + data["Id"] = this.id; + return data; + } +} + +export interface IIOperationReference { + id?: string | undefined; +} + +export class OperationReference extends IOperationReference implements IOperationReference { + id?: string | undefined; + + constructor(data?: IOperationReference) { + super(data); + this._discriminator = "OperationReference"; + } + + init(data?: any) { + super.init(data); + if (data) { + this.id = data["Id"]; + } + } + + static fromJS(data: any): OperationReference { + data = typeof data === 'object' ? data : {}; + let result = new OperationReference(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["Id"] = this.id; + super.toJSON(data); + return data; + } +} + +export interface IOperationReference extends IIOperationReference { + id?: string | undefined; +} + +export class Decision extends Result implements IDecision { + comparisonId?: ComparisonId | undefined; + riskControlType?: RiskControlType | undefined; + significance?: boolean | undefined; + pValue?: number | undefined; + lhs?: number | undefined; + significanceLevel?: number | undefined; + sampleSizeEstimate?: number | undefined; + + constructor(data?: IDecision) { + super(data); + this._discriminator = "Decision"; + } + + init(data?: any) { + super.init(data); + if (data) { + this.comparisonId = data["ComparisonId"] ? ComparisonId.fromJS(data["ComparisonId"]) : undefined; + this.riskControlType = data["RiskControlType"]; + this.significance = data["Significance"]; + this.pValue = data["PValue"]; + this.lhs = data["Lhs"]; + this.significanceLevel = data["SignificanceLevel"]; + this.sampleSizeEstimate = data["SampleSizeEstimate"]; + } + } + + static fromJS(data: any): Decision { + data = typeof data === 'object' ? data : {}; + let result = new Decision(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["ComparisonId"] = this.comparisonId ? this.comparisonId.toJSON() : undefined; + data["RiskControlType"] = this.riskControlType; + data["Significance"] = this.significance; + data["PValue"] = this.pValue; + data["Lhs"] = this.lhs; + data["SignificanceLevel"] = this.significanceLevel; + data["SampleSizeEstimate"] = this.sampleSizeEstimate; + super.toJSON(data); + return data; + } +} + +export interface IDecision extends IResult { + comparisonId?: ComparisonId | undefined; + riskControlType?: RiskControlType | undefined; + significance?: boolean | undefined; + pValue?: number | undefined; + lhs?: number | undefined; + significanceLevel?: number | undefined; + sampleSizeEstimate?: number | undefined; +} + +export class ComparisonId implements IComparisonId { + value?: string | undefined; + + constructor(data?: IComparisonId) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(data?: any) { + if (data) { + this.value = data["Value"]; + } + } + + static fromJS(data: any): ComparisonId { + data = typeof data === 'object' ? data : {}; + let result = new ComparisonId(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["Value"] = this.value; + return data; + } +} + +export interface IComparisonId { + value?: string | undefined; +} + +export class OptimizerResult extends Result implements IOptimizerResult { + topKSolutions?: Solution[] | undefined; + + constructor(data?: IOptimizerResult) { + super(data); + this._discriminator = "OptimizerResult"; + } + + init(data?: any) { + super.init(data); + if (data) { + if (data["TopKSolutions"] && data["TopKSolutions"].constructor === Array) { + this.topKSolutions = []; + for (let item of data["TopKSolutions"]) + this.topKSolutions.push(Solution.fromJS(item)); + } + } + } + + static fromJS(data: any): OptimizerResult { + data = typeof data === 'object' ? data : {}; + let result = new OptimizerResult(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + if (this.topKSolutions && this.topKSolutions.constructor === Array) { + data["TopKSolutions"] = []; + for (let item of this.topKSolutions) + data["TopKSolutions"].push(item.toJSON()); + } + super.toJSON(data); + return data; + } +} + +export interface IOptimizerResult extends IResult { + topKSolutions?: Solution[] | undefined; +} + +export class Solution implements ISolution { + solutionId?: string | undefined; + stepDescriptions?: StepDescription[] | undefined; + pipelineDescription?: PipelineDescription | undefined; + score?: Score | undefined; + naiveScore?: Score | undefined; + + constructor(data?: ISolution) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(data?: any) { + if (data) { + this.solutionId = data["SolutionId"]; + if (data["StepDescriptions"] && data["StepDescriptions"].constructor === Array) { + this.stepDescriptions = []; + for (let item of data["StepDescriptions"]) + this.stepDescriptions.push(StepDescription.fromJS(item)); + } + this.pipelineDescription = data["PipelineDescription"] ? PipelineDescription.fromJS(data["PipelineDescription"]) : undefined; + this.score = data["Score"] ? Score.fromJS(data["Score"]) : undefined; + this.naiveScore = data["NaiveScore"] ? Score.fromJS(data["NaiveScore"]) : undefined; + } + } + + static fromJS(data: any): Solution { + data = typeof data === 'object' ? data : {}; + let result = new Solution(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["SolutionId"] = this.solutionId; + if (this.stepDescriptions && this.stepDescriptions.constructor === Array) { + data["StepDescriptions"] = []; + for (let item of this.stepDescriptions) + data["StepDescriptions"].push(item.toJSON()); + } + data["PipelineDescription"] = this.pipelineDescription ? this.pipelineDescription.toJSON() : undefined; + data["Score"] = this.score ? this.score.toJSON() : undefined; + data["NaiveScore"] = this.naiveScore ? this.naiveScore.toJSON() : undefined; + return data; + } +} + +export interface ISolution { + solutionId?: string | undefined; + stepDescriptions?: StepDescription[] | undefined; + pipelineDescription?: PipelineDescription | undefined; + score?: Score | undefined; + naiveScore?: Score | undefined; +} + +export class StepDescription implements IStepDescription { + + protected _discriminator: string; + + constructor(data?: IStepDescription) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + this._discriminator = "StepDescription"; + } + + init(data?: any) { + if (data) { + } + } + + static fromJS(data: any): StepDescription { + data = typeof data === 'object' ? data : {}; + if (data["discriminator"] === "SubpipelineStepDescription") { + let result = new SubpipelineStepDescription(); + result.init(data); + return result; + } + if (data["discriminator"] === "PrimitiveStepDescription") { + let result = new PrimitiveStepDescription(); + result.init(data); + return result; + } + let result = new StepDescription(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["discriminator"] = this._discriminator; + return data; + } +} + +export interface IStepDescription { +} + +export class SubpipelineStepDescription extends StepDescription implements ISubpipelineStepDescription { + steps?: StepDescription[] | undefined; + + constructor(data?: ISubpipelineStepDescription) { + super(data); + this._discriminator = "SubpipelineStepDescription"; + } + + init(data?: any) { + super.init(data); + if (data) { + if (data["Steps"] && data["Steps"].constructor === Array) { + this.steps = []; + for (let item of data["Steps"]) + this.steps.push(StepDescription.fromJS(item)); + } + } + } + + static fromJS(data: any): SubpipelineStepDescription { + data = typeof data === 'object' ? data : {}; + let result = new SubpipelineStepDescription(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + if (this.steps && this.steps.constructor === Array) { + data["Steps"] = []; + for (let item of this.steps) + data["Steps"].push(item.toJSON()); + } + super.toJSON(data); + return data; + } +} + +export interface ISubpipelineStepDescription extends IStepDescription { + steps?: StepDescription[] | undefined; +} + +export class PipelineDescription implements IPipelineDescription { + id?: string | undefined; + name?: string | undefined; + description?: string | undefined; + inputs?: PipelineDescriptionInput[] | undefined; + outputs?: PipelineDescriptionOutput[] | undefined; + steps?: PipelineDescriptionStep[] | undefined; + + constructor(data?: IPipelineDescription) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(data?: any) { + if (data) { + this.id = data["Id"]; + this.name = data["Name"]; + this.description = data["Description"]; + if (data["Inputs"] && data["Inputs"].constructor === Array) { + this.inputs = []; + for (let item of data["Inputs"]) + this.inputs.push(PipelineDescriptionInput.fromJS(item)); + } + if (data["Outputs"] && data["Outputs"].constructor === Array) { + this.outputs = []; + for (let item of data["Outputs"]) + this.outputs.push(PipelineDescriptionOutput.fromJS(item)); + } + if (data["Steps"] && data["Steps"].constructor === Array) { + this.steps = []; + for (let item of data["Steps"]) + this.steps.push(PipelineDescriptionStep.fromJS(item)); + } + } + } + + static fromJS(data: any): PipelineDescription { + data = typeof data === 'object' ? data : {}; + let result = new PipelineDescription(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["Id"] = this.id; + data["Name"] = this.name; + data["Description"] = this.description; + if (this.inputs && this.inputs.constructor === Array) { + data["Inputs"] = []; + for (let item of this.inputs) + data["Inputs"].push(item.toJSON()); + } + if (this.outputs && this.outputs.constructor === Array) { + data["Outputs"] = []; + for (let item of this.outputs) + data["Outputs"].push(item.toJSON()); + } + if (this.steps && this.steps.constructor === Array) { + data["Steps"] = []; + for (let item of this.steps) + data["Steps"].push(item.toJSON()); + } + return data; + } +} + +export interface IPipelineDescription { + id?: string | undefined; + name?: string | undefined; + description?: string | undefined; + inputs?: PipelineDescriptionInput[] | undefined; + outputs?: PipelineDescriptionOutput[] | undefined; + steps?: PipelineDescriptionStep[] | undefined; +} + +export class PipelineDescriptionInput implements IPipelineDescriptionInput { + name?: string | undefined; + + constructor(data?: IPipelineDescriptionInput) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(data?: any) { + if (data) { + this.name = data["Name"]; + } + } + + static fromJS(data: any): PipelineDescriptionInput { + data = typeof data === 'object' ? data : {}; + let result = new PipelineDescriptionInput(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["Name"] = this.name; + return data; + } +} + +export interface IPipelineDescriptionInput { + name?: string | undefined; +} + +export class PipelineDescriptionOutput implements IPipelineDescriptionOutput { + name?: string | undefined; + data?: string | undefined; + + constructor(data?: IPipelineDescriptionOutput) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(data?: any) { + if (data) { + this.name = data["Name"]; + this.data = data["Data"]; + } + } + + static fromJS(data: any): PipelineDescriptionOutput { + data = typeof data === 'object' ? data : {}; + let result = new PipelineDescriptionOutput(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["Name"] = this.name; + data["Data"] = this.data; + return data; + } +} + +export interface IPipelineDescriptionOutput { + name?: string | undefined; + data?: string | undefined; +} + +export class PipelineDescriptionStep implements IPipelineDescriptionStep { + outputs?: StepOutput[] | undefined; + + protected _discriminator: string; + + constructor(data?: IPipelineDescriptionStep) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + this._discriminator = "PipelineDescriptionStep"; + } + + init(data?: any) { + if (data) { + if (data["Outputs"] && data["Outputs"].constructor === Array) { + this.outputs = []; + for (let item of data["Outputs"]) + this.outputs.push(StepOutput.fromJS(item)); + } + } + } + + static fromJS(data: any): PipelineDescriptionStep { + data = typeof data === 'object' ? data : {}; + if (data["discriminator"] === "PlaceholderPipelineDescriptionStep") { + let result = new PlaceholderPipelineDescriptionStep(); + result.init(data); + return result; + } + if (data["discriminator"] === "SubpipelinePipelineDescriptionStep") { + let result = new SubpipelinePipelineDescriptionStep(); + result.init(data); + return result; + } + if (data["discriminator"] === "PrimitivePipelineDescriptionStep") { + let result = new PrimitivePipelineDescriptionStep(); + result.init(data); + return result; + } + let result = new PipelineDescriptionStep(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["discriminator"] = this._discriminator; + if (this.outputs && this.outputs.constructor === Array) { + data["Outputs"] = []; + for (let item of this.outputs) + data["Outputs"].push(item.toJSON()); + } + return data; + } +} + +export interface IPipelineDescriptionStep { + outputs?: StepOutput[] | undefined; +} + +export class StepOutput implements IStepOutput { + id?: string | undefined; + + constructor(data?: IStepOutput) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(data?: any) { + if (data) { + this.id = data["Id"]; + } + } + + static fromJS(data: any): StepOutput { + data = typeof data === 'object' ? data : {}; + let result = new StepOutput(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["Id"] = this.id; + return data; + } +} + +export interface IStepOutput { + id?: string | undefined; +} + +export class PlaceholderPipelineDescriptionStep extends PipelineDescriptionStep implements IPlaceholderPipelineDescriptionStep { + inputs?: StepInput[] | undefined; + + constructor(data?: IPlaceholderPipelineDescriptionStep) { + super(data); + this._discriminator = "PlaceholderPipelineDescriptionStep"; + } + + init(data?: any) { + super.init(data); + if (data) { + if (data["Inputs"] && data["Inputs"].constructor === Array) { + this.inputs = []; + for (let item of data["Inputs"]) + this.inputs.push(StepInput.fromJS(item)); + } + } + } + + static fromJS(data: any): PlaceholderPipelineDescriptionStep { + data = typeof data === 'object' ? data : {}; + let result = new PlaceholderPipelineDescriptionStep(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + if (this.inputs && this.inputs.constructor === Array) { + data["Inputs"] = []; + for (let item of this.inputs) + data["Inputs"].push(item.toJSON()); + } + super.toJSON(data); + return data; + } +} + +export interface IPlaceholderPipelineDescriptionStep extends IPipelineDescriptionStep { + inputs?: StepInput[] | undefined; +} + +export class StepInput implements IStepInput { + data?: string | undefined; + + constructor(data?: IStepInput) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(data?: any) { + if (data) { + this.data = data["Data"]; + } + } + + static fromJS(data: any): StepInput { + data = typeof data === 'object' ? data : {}; + let result = new StepInput(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["Data"] = this.data; + return data; + } +} + +export interface IStepInput { + data?: string | undefined; +} + +export class SubpipelinePipelineDescriptionStep extends PipelineDescriptionStep implements ISubpipelinePipelineDescriptionStep { + pipelineDescription?: PipelineDescription | undefined; + inputs?: StepInput[] | undefined; + + constructor(data?: ISubpipelinePipelineDescriptionStep) { + super(data); + this._discriminator = "SubpipelinePipelineDescriptionStep"; + } + + init(data?: any) { + super.init(data); + if (data) { + this.pipelineDescription = data["PipelineDescription"] ? PipelineDescription.fromJS(data["PipelineDescription"]) : undefined; + if (data["Inputs"] && data["Inputs"].constructor === Array) { + this.inputs = []; + for (let item of data["Inputs"]) + this.inputs.push(StepInput.fromJS(item)); + } + } + } + + static fromJS(data: any): SubpipelinePipelineDescriptionStep { + data = typeof data === 'object' ? data : {}; + let result = new SubpipelinePipelineDescriptionStep(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["PipelineDescription"] = this.pipelineDescription ? this.pipelineDescription.toJSON() : undefined; + if (this.inputs && this.inputs.constructor === Array) { + data["Inputs"] = []; + for (let item of this.inputs) + data["Inputs"].push(item.toJSON()); + } + super.toJSON(data); + return data; + } +} + +export interface ISubpipelinePipelineDescriptionStep extends IPipelineDescriptionStep { + pipelineDescription?: PipelineDescription | undefined; + inputs?: StepInput[] | undefined; +} + +export class PrimitivePipelineDescriptionStep extends PipelineDescriptionStep implements IPrimitivePipelineDescriptionStep { + primitive?: Primitive | undefined; + arguments?: { [key: string]: PrimitiveStepArgument; } | undefined; + hyperparams?: { [key: string]: PrimitiveStepHyperparameter; } | undefined; + + constructor(data?: IPrimitivePipelineDescriptionStep) { + super(data); + this._discriminator = "PrimitivePipelineDescriptionStep"; + } + + init(data?: any) { + super.init(data); + if (data) { + this.primitive = data["Primitive"] ? Primitive.fromJS(data["Primitive"]) : undefined; + if (data["Arguments"]) { + this.arguments = {}; + for (let key in data["Arguments"]) { + if (data["Arguments"].hasOwnProperty(key)) + this.arguments[key] = data["Arguments"][key] ? PrimitiveStepArgument.fromJS(data["Arguments"][key]) : new PrimitiveStepArgument(); + } + } + if (data["Hyperparams"]) { + this.hyperparams = {}; + for (let key in data["Hyperparams"]) { + if (data["Hyperparams"].hasOwnProperty(key)) + this.hyperparams[key] = data["Hyperparams"][key] ? PrimitiveStepHyperparameter.fromJS(data["Hyperparams"][key]) : new PrimitiveStepHyperparameter(); + } + } + } + } + + static fromJS(data: any): PrimitivePipelineDescriptionStep { + data = typeof data === 'object' ? data : {}; + let result = new PrimitivePipelineDescriptionStep(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["Primitive"] = this.primitive ? this.primitive.toJSON() : undefined; + if (this.arguments) { + data["Arguments"] = {}; + for (let key in this.arguments) { + if (this.arguments.hasOwnProperty(key)) + data["Arguments"][key] = this.arguments[key]; + } + } + if (this.hyperparams) { + data["Hyperparams"] = {}; + for (let key in this.hyperparams) { + if (this.hyperparams.hasOwnProperty(key)) + data["Hyperparams"][key] = this.hyperparams[key]; + } + } + super.toJSON(data); + return data; + } +} + +export interface IPrimitivePipelineDescriptionStep extends IPipelineDescriptionStep { + primitive?: Primitive | undefined; + arguments?: { [key: string]: PrimitiveStepArgument; } | undefined; + hyperparams?: { [key: string]: PrimitiveStepHyperparameter; } | undefined; +} + +export class Primitive implements IPrimitive { + id?: string | undefined; + version?: string | undefined; + pythonPath?: string | undefined; + name?: string | undefined; + digest?: string | undefined; + + constructor(data?: IPrimitive) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(data?: any) { + if (data) { + this.id = data["Id"]; + this.version = data["Version"]; + this.pythonPath = data["PythonPath"]; + this.name = data["Name"]; + this.digest = data["Digest"]; + } + } + + static fromJS(data: any): Primitive { + data = typeof data === 'object' ? data : {}; + let result = new Primitive(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["Id"] = this.id; + data["Version"] = this.version; + data["PythonPath"] = this.pythonPath; + data["Name"] = this.name; + data["Digest"] = this.digest; + return data; + } +} + +export interface IPrimitive { + id?: string | undefined; + version?: string | undefined; + pythonPath?: string | undefined; + name?: string | undefined; + digest?: string | undefined; +} + +export class PrimitiveStepHyperparameter implements IPrimitiveStepHyperparameter { + + protected _discriminator: string; + + constructor(data?: IPrimitiveStepHyperparameter) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + this._discriminator = "PrimitiveStepHyperparameter"; + } + + init(data?: any) { + if (data) { + } + } + + static fromJS(data: any): PrimitiveStepHyperparameter { + data = typeof data === 'object' ? data : {}; + if (data["discriminator"] === "PrimitiveStepArgument") { + let result = new PrimitiveStepArgument(); + result.init(data); + return result; + } + if (data["discriminator"] === "DataArguments") { + let result = new DataArguments(); + result.init(data); + return result; + } + if (data["discriminator"] === "PrimitiveArgument") { + let result = new PrimitiveArgument(); + result.init(data); + return result; + } + if (data["discriminator"] === "PrimitiveArguments") { + let result = new PrimitiveArguments(); + result.init(data); + return result; + } + if (data["discriminator"] === "ValueArgument") { + let result = new ValueArgument(); + result.init(data); + return result; + } + if (data["discriminator"] === "ContainerArgument") { + let result = new ContainerArgument(); + result.init(data); + return result; + } + if (data["discriminator"] === "DataArgument") { + let result = new DataArgument(); + result.init(data); + return result; + } + let result = new PrimitiveStepHyperparameter(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["discriminator"] = this._discriminator; + return data; + } +} + +export interface IPrimitiveStepHyperparameter { +} + +export class PrimitiveStepArgument extends PrimitiveStepHyperparameter implements IPrimitiveStepArgument { + + protected _discriminator: string; + + constructor(data?: IPrimitiveStepArgument) { + super(data); + this._discriminator = "PrimitiveStepArgument"; + } + + init(data?: any) { + super.init(data); + if (data) { + } + } + + static fromJS(data: any): PrimitiveStepArgument { + data = typeof data === 'object' ? data : {}; + if (data["discriminator"] === "ContainerArgument") { + let result = new ContainerArgument(); + result.init(data); + return result; + } + if (data["discriminator"] === "DataArgument") { + let result = new DataArgument(); + result.init(data); + return result; + } + let result = new PrimitiveStepArgument(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["discriminator"] = this._discriminator; + super.toJSON(data); + return data; + } +} + +export interface IPrimitiveStepArgument extends IPrimitiveStepHyperparameter { +} + +export class DataArguments extends PrimitiveStepHyperparameter implements IDataArguments { + data?: string[] | undefined; + + constructor(data?: IDataArguments) { + super(data); + this._discriminator = "DataArguments"; + } + + init(data?: any) { + super.init(data); + if (data) { + if (data["Data"] && data["Data"].constructor === Array) { + this.data = []; + for (let item of data["Data"]) + this.data.push(item); + } + } + } + + static fromJS(data: any): DataArguments { + data = typeof data === 'object' ? data : {}; + let result = new DataArguments(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + if (this.data && this.data.constructor === Array) { + data["Data"] = []; + for (let item of this.data) + data["Data"].push(item); + } + super.toJSON(data); + return data; + } +} + +export interface IDataArguments extends IPrimitiveStepHyperparameter { + data?: string[] | undefined; +} + +export class PrimitiveArgument extends PrimitiveStepHyperparameter implements IPrimitiveArgument { + data?: number | undefined; + + constructor(data?: IPrimitiveArgument) { + super(data); + this._discriminator = "PrimitiveArgument"; + } + + init(data?: any) { + super.init(data); + if (data) { + this.data = data["Data"]; + } + } + + static fromJS(data: any): PrimitiveArgument { + data = typeof data === 'object' ? data : {}; + let result = new PrimitiveArgument(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["Data"] = this.data; + super.toJSON(data); + return data; + } +} + +export interface IPrimitiveArgument extends IPrimitiveStepHyperparameter { + data?: number | undefined; +} + +export class PrimitiveArguments extends PrimitiveStepHyperparameter implements IPrimitiveArguments { + data?: number[] | undefined; + + constructor(data?: IPrimitiveArguments) { + super(data); + this._discriminator = "PrimitiveArguments"; + } + + init(data?: any) { + super.init(data); + if (data) { + if (data["Data"] && data["Data"].constructor === Array) { + this.data = []; + for (let item of data["Data"]) + this.data.push(item); + } + } + } + + static fromJS(data: any): PrimitiveArguments { + data = typeof data === 'object' ? data : {}; + let result = new PrimitiveArguments(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + if (this.data && this.data.constructor === Array) { + data["Data"] = []; + for (let item of this.data) + data["Data"].push(item); + } + super.toJSON(data); + return data; + } +} + +export interface IPrimitiveArguments extends IPrimitiveStepHyperparameter { + data?: number[] | undefined; +} + +export class ValueArgument extends PrimitiveStepHyperparameter implements IValueArgument { + data?: Value | undefined; + + constructor(data?: IValueArgument) { + super(data); + this._discriminator = "ValueArgument"; + } + + init(data?: any) { + super.init(data); + if (data) { + this.data = data["Data"] ? Value.fromJS(data["Data"]) : undefined; + } + } + + static fromJS(data: any): ValueArgument { + data = typeof data === 'object' ? data : {}; + let result = new ValueArgument(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["Data"] = this.data ? this.data.toJSON() : undefined; + super.toJSON(data); + return data; + } +} + +export interface IValueArgument extends IPrimitiveStepHyperparameter { + data?: Value | undefined; +} + +export abstract class Value implements IValue { + + protected _discriminator: string; + + constructor(data?: IValue) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + this._discriminator = "Value"; + } + + init(data?: any) { + if (data) { + } + } + + static fromJS(data: any): Value { + data = typeof data === 'object' ? data : {}; + if (data["discriminator"] === "ErrorValue") { + let result = new ErrorValue(); + result.init(data); + return result; + } + if (data["discriminator"] === "DoubleValue") { + let result = new DoubleValue(); + result.init(data); + return result; + } + if (data["discriminator"] === "LongValue") { + let result = new LongValue(); + result.init(data); + return result; + } + if (data["discriminator"] === "BoolValue") { + let result = new BoolValue(); + result.init(data); + return result; + } + if (data["discriminator"] === "StringValue") { + let result = new StringValue(); + result.init(data); + return result; + } + if (data["discriminator"] === "DatasetUriValue") { + let result = new DatasetUriValue(); + result.init(data); + return result; + } + if (data["discriminator"] === "CsvUriValue") { + let result = new CsvUriValue(); + result.init(data); + return result; + } + if (data["discriminator"] === "PickleUriValue") { + let result = new PickleUriValue(); + result.init(data); + return result; + } + if (data["discriminator"] === "PickleBlobValue") { + let result = new PickleBlobValue(); + result.init(data); + return result; + } + if (data["discriminator"] === "PlasmaIdValue") { + let result = new PlasmaIdValue(); + result.init(data); + return result; + } + if (data["discriminator"] === "BytesValue") { + let result = new BytesValue(); + result.init(data); + return result; + } + if (data["discriminator"] === "ListValue") { + let result = new ListValue(); + result.init(data); + return result; + } + throw new Error("The abstract class 'Value' cannot be instantiated."); + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["discriminator"] = this._discriminator; + return data; + } +} + +export interface IValue { +} + +export class ErrorValue extends Value implements IErrorValue { + message?: string | undefined; + + constructor(data?: IErrorValue) { + super(data); + this._discriminator = "ErrorValue"; + } + + init(data?: any) { + super.init(data); + if (data) { + this.message = data["Message"]; + } + } + + static fromJS(data: any): ErrorValue { + data = typeof data === 'object' ? data : {}; + let result = new ErrorValue(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["Message"] = this.message; + super.toJSON(data); + return data; + } +} + +export interface IErrorValue extends IValue { + message?: string | undefined; +} + +export class DoubleValue extends Value implements IDoubleValue { + value?: number | undefined; + + constructor(data?: IDoubleValue) { + super(data); + this._discriminator = "DoubleValue"; + } + + init(data?: any) { + super.init(data); + if (data) { + this.value = data["Value"]; + } + } + + static fromJS(data: any): DoubleValue { + data = typeof data === 'object' ? data : {}; + let result = new DoubleValue(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["Value"] = this.value; + super.toJSON(data); + return data; + } +} + +export interface IDoubleValue extends IValue { + value?: number | undefined; +} + +export class LongValue extends Value implements ILongValue { + value?: number | undefined; + + constructor(data?: ILongValue) { + super(data); + this._discriminator = "LongValue"; + } + + init(data?: any) { + super.init(data); + if (data) { + this.value = data["Value"]; + } + } + + static fromJS(data: any): LongValue { + data = typeof data === 'object' ? data : {}; + let result = new LongValue(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["Value"] = this.value; + super.toJSON(data); + return data; + } +} + +export interface ILongValue extends IValue { + value?: number | undefined; +} + +export class BoolValue extends Value implements IBoolValue { + value?: boolean | undefined; + + constructor(data?: IBoolValue) { + super(data); + this._discriminator = "BoolValue"; + } + + init(data?: any) { + super.init(data); + if (data) { + this.value = data["Value"]; + } + } + + static fromJS(data: any): BoolValue { + data = typeof data === 'object' ? data : {}; + let result = new BoolValue(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["Value"] = this.value; + super.toJSON(data); + return data; + } +} + +export interface IBoolValue extends IValue { + value?: boolean | undefined; +} + +export class StringValue extends Value implements IStringValue { + value?: string | undefined; + + constructor(data?: IStringValue) { + super(data); + this._discriminator = "StringValue"; + } + + init(data?: any) { + super.init(data); + if (data) { + this.value = data["Value"]; + } + } + + static fromJS(data: any): StringValue { + data = typeof data === 'object' ? data : {}; + let result = new StringValue(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["Value"] = this.value; + super.toJSON(data); + return data; + } +} + +export interface IStringValue extends IValue { + value?: string | undefined; +} + +export class DatasetUriValue extends Value implements IDatasetUriValue { + value?: string | undefined; + + constructor(data?: IDatasetUriValue) { + super(data); + this._discriminator = "DatasetUriValue"; + } + + init(data?: any) { + super.init(data); + if (data) { + this.value = data["Value"]; + } + } + + static fromJS(data: any): DatasetUriValue { + data = typeof data === 'object' ? data : {}; + let result = new DatasetUriValue(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["Value"] = this.value; + super.toJSON(data); + return data; + } +} + +export interface IDatasetUriValue extends IValue { + value?: string | undefined; +} + +export class CsvUriValue extends Value implements ICsvUriValue { + value?: string | undefined; + + constructor(data?: ICsvUriValue) { + super(data); + this._discriminator = "CsvUriValue"; + } + + init(data?: any) { + super.init(data); + if (data) { + this.value = data["Value"]; + } + } + + static fromJS(data: any): CsvUriValue { + data = typeof data === 'object' ? data : {}; + let result = new CsvUriValue(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["Value"] = this.value; + super.toJSON(data); + return data; + } +} + +export interface ICsvUriValue extends IValue { + value?: string | undefined; +} + +export class PickleUriValue extends Value implements IPickleUriValue { + value?: string | undefined; + + constructor(data?: IPickleUriValue) { + super(data); + this._discriminator = "PickleUriValue"; + } + + init(data?: any) { + super.init(data); + if (data) { + this.value = data["Value"]; + } + } + + static fromJS(data: any): PickleUriValue { + data = typeof data === 'object' ? data : {}; + let result = new PickleUriValue(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["Value"] = this.value; + super.toJSON(data); + return data; + } +} + +export interface IPickleUriValue extends IValue { + value?: string | undefined; +} + +export class PickleBlobValue extends Value implements IPickleBlobValue { + value?: string | undefined; + + constructor(data?: IPickleBlobValue) { + super(data); + this._discriminator = "PickleBlobValue"; + } + + init(data?: any) { + super.init(data); + if (data) { + this.value = data["Value"]; + } + } + + static fromJS(data: any): PickleBlobValue { + data = typeof data === 'object' ? data : {}; + let result = new PickleBlobValue(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["Value"] = this.value; + super.toJSON(data); + return data; + } +} + +export interface IPickleBlobValue extends IValue { + value?: string | undefined; +} + +export class PlasmaIdValue extends Value implements IPlasmaIdValue { + value?: string | undefined; + + constructor(data?: IPlasmaIdValue) { + super(data); + this._discriminator = "PlasmaIdValue"; + } + + init(data?: any) { + super.init(data); + if (data) { + this.value = data["Value"]; + } + } + + static fromJS(data: any): PlasmaIdValue { + data = typeof data === 'object' ? data : {}; + let result = new PlasmaIdValue(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["Value"] = this.value; + super.toJSON(data); + return data; + } +} + +export interface IPlasmaIdValue extends IValue { + value?: string | undefined; +} + +export class BytesValue extends Value implements IBytesValue { + value?: string | undefined; + + constructor(data?: IBytesValue) { + super(data); + this._discriminator = "BytesValue"; + } + + init(data?: any) { + super.init(data); + if (data) { + this.value = data["Value"]; + } + } + + static fromJS(data: any): BytesValue { + data = typeof data === 'object' ? data : {}; + let result = new BytesValue(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["Value"] = this.value; + super.toJSON(data); + return data; + } +} + +export interface IBytesValue extends IValue { + value?: string | undefined; +} + +export class ContainerArgument extends PrimitiveStepArgument implements IContainerArgument { + data?: string | undefined; + + constructor(data?: IContainerArgument) { + super(data); + this._discriminator = "ContainerArgument"; + } + + init(data?: any) { + super.init(data); + if (data) { + this.data = data["Data"]; + } + } + + static fromJS(data: any): ContainerArgument { + data = typeof data === 'object' ? data : {}; + let result = new ContainerArgument(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["Data"] = this.data; + super.toJSON(data); + return data; + } +} + +export interface IContainerArgument extends IPrimitiveStepArgument { + data?: string | undefined; +} + +export class Score implements IScore { + metricType?: MetricType | undefined; + value?: number | undefined; + + constructor(data?: IScore) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(data?: any) { + if (data) { + this.metricType = data["MetricType"]; + this.value = data["Value"]; + } + } + + static fromJS(data: any): Score { + data = typeof data === 'object' ? data : {}; + let result = new Score(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["MetricType"] = this.metricType; + data["Value"] = this.value; + return data; + } +} + +export interface IScore { + metricType?: MetricType | undefined; + value?: number | undefined; +} + +export class ExampleResult extends Result implements IExampleResult { + resultValues?: { [key: string]: string; } | undefined; + message?: string | undefined; + + constructor(data?: IExampleResult) { + super(data); + this._discriminator = "ExampleResult"; + } + + init(data?: any) { + super.init(data); + if (data) { + if (data["ResultValues"]) { + this.resultValues = {}; + for (let key in data["ResultValues"]) { + if (data["ResultValues"].hasOwnProperty(key)) + this.resultValues[key] = data["ResultValues"][key]; + } + } + this.message = data["Message"]; + } + } + + static fromJS(data: any): ExampleResult { + data = typeof data === 'object' ? data : {}; + let result = new ExampleResult(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + if (this.resultValues) { + data["ResultValues"] = {}; + for (let key in this.resultValues) { + if (this.resultValues.hasOwnProperty(key)) + data["ResultValues"][key] = this.resultValues[key]; + } + } + data["Message"] = this.message; + super.toJSON(data); + return data; + } +} + +export interface IExampleResult extends IResult { + resultValues?: { [key: string]: string; } | undefined; + message?: string | undefined; +} + +export class NewModelOperationResult extends ModelOperationResult implements INewModelOperationResult { + + constructor(data?: INewModelOperationResult) { + super(data); + this._discriminator = "NewModelOperationResult"; + } + + init(data?: any) { + super.init(data); + if (data) { + } + } + + static fromJS(data: any): NewModelOperationResult { + data = typeof data === 'object' ? data : {}; + let result = new NewModelOperationResult(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + super.toJSON(data); + return data; + } +} + +export interface INewModelOperationResult extends IModelOperationResult { +} + +export class AddComparisonResult extends ModelOperationResult implements IAddComparisonResult { + comparisonId?: ComparisonId | undefined; + + constructor(data?: IAddComparisonResult) { + super(data); + this._discriminator = "AddComparisonResult"; + } + + init(data?: any) { + super.init(data); + if (data) { + this.comparisonId = data["ComparisonId"] ? ComparisonId.fromJS(data["ComparisonId"]) : undefined; + } + } + + static fromJS(data: any): AddComparisonResult { + data = typeof data === 'object' ? data : {}; + let result = new AddComparisonResult(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["ComparisonId"] = this.comparisonId ? this.comparisonId.toJSON() : undefined; + super.toJSON(data); + return data; + } +} + +export interface IAddComparisonResult extends IModelOperationResult { + comparisonId?: ComparisonId | undefined; +} + +export class GetModelStateResult extends ModelOperationResult implements IGetModelStateResult { + decisions?: Decision[] | undefined; + startingWealth?: number | undefined; + currentWealth?: number | undefined; + + constructor(data?: IGetModelStateResult) { + super(data); + this._discriminator = "GetModelStateResult"; + } + + init(data?: any) { + super.init(data); + if (data) { + if (data["Decisions"] && data["Decisions"].constructor === Array) { + this.decisions = []; + for (let item of data["Decisions"]) + this.decisions.push(Decision.fromJS(item)); + } + this.startingWealth = data["StartingWealth"]; + this.currentWealth = data["CurrentWealth"]; + } + } + + static fromJS(data: any): GetModelStateResult { + data = typeof data === 'object' ? data : {}; + let result = new GetModelStateResult(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + if (this.decisions && this.decisions.constructor === Array) { + data["Decisions"] = []; + for (let item of this.decisions) + data["Decisions"].push(item.toJSON()); + } + data["StartingWealth"] = this.startingWealth; + data["CurrentWealth"] = this.currentWealth; + super.toJSON(data); + return data; + } +} + +export interface IGetModelStateResult extends IModelOperationResult { + decisions?: Decision[] | undefined; + startingWealth?: number | undefined; + currentWealth?: number | undefined; +} + +export class AggregateKey implements IAggregateKey { + aggregateParameterIndex?: number | undefined; + brushIndex?: number | undefined; + + constructor(data?: IAggregateKey) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(data?: any) { + if (data) { + this.aggregateParameterIndex = data["AggregateParameterIndex"]; + this.brushIndex = data["BrushIndex"]; + } + } + + static fromJS(data: any): AggregateKey { + data = typeof data === 'object' ? data : {}; + let result = new AggregateKey(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["AggregateParameterIndex"] = this.aggregateParameterIndex; + data["BrushIndex"] = this.brushIndex; + return data; + } +} + +export interface IAggregateKey { + aggregateParameterIndex?: number | undefined; + brushIndex?: number | undefined; +} + +export abstract class IResult implements IIResult { + + constructor(data?: IIResult) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(data?: any) { + if (data) { + } + } + + static fromJS(data: any): IResult { + data = typeof data === 'object' ? data : {}; + throw new Error("The abstract class 'IResult' cannot be instantiated."); + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + return data; + } +} + +export interface IIResult { +} + +export class DataArgument extends PrimitiveStepArgument implements IDataArgument { + data?: string | undefined; + + constructor(data?: IDataArgument) { + super(data); + this._discriminator = "DataArgument"; + } + + init(data?: any) { + super.init(data); + if (data) { + this.data = data["Data"]; + } + } + + static fromJS(data: any): DataArgument { + data = typeof data === 'object' ? data : {}; + let result = new DataArgument(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["Data"] = this.data; + super.toJSON(data); + return data; + } +} + +export interface IDataArgument extends IPrimitiveStepArgument { + data?: string | undefined; +} + +export class ListValue extends Value implements IListValue { + items?: Value[] | undefined; + + constructor(data?: IListValue) { + super(data); + this._discriminator = "ListValue"; + } + + init(data?: any) { + super.init(data); + if (data) { + if (data["Items"] && data["Items"].constructor === Array) { + this.items = []; + for (let item of data["Items"]) + this.items.push(Value.fromJS(item)); + } + } + } + + static fromJS(data: any): ListValue { + data = typeof data === 'object' ? data : {}; + let result = new ListValue(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + if (this.items && this.items.constructor === Array) { + data["Items"] = []; + for (let item of this.items) + data["Items"].push(item.toJSON()); + } + super.toJSON(data); + return data; + } +} + +export interface IListValue extends IValue { + items?: Value[] | undefined; +} + +export class Metrics implements IMetrics { + averageAccuracy?: number | undefined; + averageRSquared?: number | undefined; + f1Macro?: number | undefined; + + constructor(data?: IMetrics) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(data?: any) { + if (data) { + this.averageAccuracy = data["AverageAccuracy"]; + this.averageRSquared = data["AverageRSquared"]; + this.f1Macro = data["F1Macro"]; + } + } + + static fromJS(data: any): Metrics { + data = typeof data === 'object' ? data : {}; + let result = new Metrics(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["AverageAccuracy"] = this.averageAccuracy; + data["AverageRSquared"] = this.averageRSquared; + data["F1Macro"] = this.f1Macro; + return data; + } +} + +export interface IMetrics { + averageAccuracy?: number | undefined; + averageRSquared?: number | undefined; + f1Macro?: number | undefined; +} + +export class FeatureImportanceOperationParameters extends DistOperationParameters implements IFeatureImportanceOperationParameters { + solutionId?: string | undefined; + + constructor(data?: IFeatureImportanceOperationParameters) { + super(data); + this._discriminator = "FeatureImportanceOperationParameters"; + } + + init(data?: any) { + super.init(data); + if (data) { + this.solutionId = data["SolutionId"]; + } + } + + static fromJS(data: any): FeatureImportanceOperationParameters { + data = typeof data === 'object' ? data : {}; + let result = new FeatureImportanceOperationParameters(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["SolutionId"] = this.solutionId; + super.toJSON(data); + return data; + } +} + +export interface IFeatureImportanceOperationParameters extends IDistOperationParameters { + solutionId?: string | undefined; +} + +export class FeatureImportanceResult extends Result implements IFeatureImportanceResult { + featureImportances?: { [key: string]: TupleOfDoubleAndDouble; } | undefined; + + constructor(data?: IFeatureImportanceResult) { + super(data); + this._discriminator = "FeatureImportanceResult"; + } + + init(data?: any) { + super.init(data); + if (data) { + if (data["FeatureImportances"]) { + this.featureImportances = {}; + for (let key in data["FeatureImportances"]) { + if (data["FeatureImportances"].hasOwnProperty(key)) + this.featureImportances[key] = data["FeatureImportances"][key] ? TupleOfDoubleAndDouble.fromJS(data["FeatureImportances"][key]) : new TupleOfDoubleAndDouble(); + } + } + } + } + + static fromJS(data: any): FeatureImportanceResult { + data = typeof data === 'object' ? data : {}; + let result = new FeatureImportanceResult(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + if (this.featureImportances) { + data["FeatureImportances"] = {}; + for (let key in this.featureImportances) { + if (this.featureImportances.hasOwnProperty(key)) + data["FeatureImportances"][key] = this.featureImportances[key]; + } + } + super.toJSON(data); + return data; + } +} + +export interface IFeatureImportanceResult extends IResult { + featureImportances?: { [key: string]: TupleOfDoubleAndDouble; } | undefined; +} + +export class TupleOfDoubleAndDouble implements ITupleOfDoubleAndDouble { + item1?: number | undefined; + item2?: number | undefined; + + constructor(data?: ITupleOfDoubleAndDouble) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(data?: any) { + if (data) { + this.item1 = data["Item1"]; + this.item2 = data["Item2"]; + } + } + + static fromJS(data: any): TupleOfDoubleAndDouble { + data = typeof data === 'object' ? data : {}; + let result = new TupleOfDoubleAndDouble(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["Item1"] = this.item1; + data["Item2"] = this.item2; + return data; + } +} + +export interface ITupleOfDoubleAndDouble { + item1?: number | undefined; + item2?: number | undefined; +} + +export class PrimitiveStepDescription extends StepDescription implements IPrimitiveStepDescription { + hyperparams?: { [key: string]: Value; } | undefined; + + constructor(data?: IPrimitiveStepDescription) { + super(data); + this._discriminator = "PrimitiveStepDescription"; + } + + init(data?: any) { + super.init(data); + if (data) { + if (data["Hyperparams"]) { + this.hyperparams = {}; + for (let key in data["Hyperparams"]) { + if (data["Hyperparams"].hasOwnProperty(key)) + this.hyperparams[key] = data["Hyperparams"][key] ? Value.fromJS(data["Hyperparams"][key]) : undefined; + } + } + } + } + + static fromJS(data: any): PrimitiveStepDescription { + data = typeof data === 'object' ? data : {}; + let result = new PrimitiveStepDescription(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + if (this.hyperparams) { + data["Hyperparams"] = {}; + for (let key in this.hyperparams) { + if (this.hyperparams.hasOwnProperty(key)) + data["Hyperparams"][key] = this.hyperparams[key]; + } + } + super.toJSON(data); + return data; + } +} + +export interface IPrimitiveStepDescription extends IStepDescription { + hyperparams?: { [key: string]: Value; } | undefined; +} + +export enum ValueType { + VALUE_TYPE_UNDEFINED = 0, + RAW = 1, + DATASET_URI = 2, + CSV_URI = 3, + PICKLE_URI = 4, + PICKLE_BLOB = 5, + PLASMA_ID = 6, +} + +export class DatamartSearchParameters implements IDatamartSearchParameters { + adapterName?: string | undefined; + queryJson?: string | undefined; + + constructor(data?: IDatamartSearchParameters) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(data?: any) { + if (data) { + this.adapterName = data["AdapterName"]; + this.queryJson = data["QueryJson"]; + } + } + + static fromJS(data: any): DatamartSearchParameters { + data = typeof data === 'object' ? data : {}; + let result = new DatamartSearchParameters(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["AdapterName"] = this.adapterName; + data["QueryJson"] = this.queryJson; + return data; + } +} + +export interface IDatamartSearchParameters { + adapterName?: string | undefined; + queryJson?: string | undefined; +} + +export class DatamartAugmentParameters implements IDatamartAugmentParameters { + adapterName?: string | undefined; + augmentationJson?: string | undefined; + numberOfSamples?: number | undefined; + augmentedAdapterName?: string | undefined; + + constructor(data?: IDatamartAugmentParameters) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(data?: any) { + if (data) { + this.adapterName = data["AdapterName"]; + this.augmentationJson = data["AugmentationJson"]; + this.numberOfSamples = data["NumberOfSamples"]; + this.augmentedAdapterName = data["AugmentedAdapterName"]; + } + } + + static fromJS(data: any): DatamartAugmentParameters { + data = typeof data === 'object' ? data : {}; + let result = new DatamartAugmentParameters(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["AdapterName"] = this.adapterName; + data["AugmentationJson"] = this.augmentationJson; + data["NumberOfSamples"] = this.numberOfSamples; + data["AugmentedAdapterName"] = this.augmentedAdapterName; + return data; + } +} + +export interface IDatamartAugmentParameters { + adapterName?: string | undefined; + augmentationJson?: string | undefined; + numberOfSamples?: number | undefined; + augmentedAdapterName?: string | undefined; +} + +export class RawDataResult extends DistResult implements IRawDataResult { + samples?: { [key: string]: any[]; } | undefined; + weightedWords?: { [key: string]: Word[]; } | undefined; + + constructor(data?: IRawDataResult) { + super(data); + this._discriminator = "RawDataResult"; + } + + init(data?: any) { + super.init(data); + if (data) { + if (data["Samples"]) { + this.samples = {}; + for (let key in data["Samples"]) { + if (data["Samples"].hasOwnProperty(key)) + this.samples[key] = data["Samples"][key] !== undefined ? data["Samples"][key] : []; + } + } + if (data["WeightedWords"]) { + this.weightedWords = {}; + for (let key in data["WeightedWords"]) { + if (data["WeightedWords"].hasOwnProperty(key)) + this.weightedWords[key] = data["WeightedWords"][key] ? data["WeightedWords"][key].map((i: any) => Word.fromJS(i)) : []; + } + } + } + } + + static fromJS(data: any): RawDataResult { + data = typeof data === 'object' ? data : {}; + let result = new RawDataResult(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + if (this.samples) { + data["Samples"] = {}; + for (let key in this.samples) { + if (this.samples.hasOwnProperty(key)) + data["Samples"][key] = this.samples[key]; + } + } + if (this.weightedWords) { + data["WeightedWords"] = {}; + for (let key in this.weightedWords) { + if (this.weightedWords.hasOwnProperty(key)) + data["WeightedWords"][key] = this.weightedWords[key]; + } + } + super.toJSON(data); + return data; + } +} + +export interface IRawDataResult extends IDistResult { + samples?: { [key: string]: any[]; } | undefined; + weightedWords?: { [key: string]: Word[]; } | undefined; +} + +export class Word implements IWord { + text?: string | undefined; + occurrences?: number | undefined; + stem?: string | undefined; + isWordGroup?: boolean | undefined; + + constructor(data?: IWord) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(data?: any) { + if (data) { + this.text = data["Text"]; + this.occurrences = data["Occurrences"]; + this.stem = data["Stem"]; + this.isWordGroup = data["IsWordGroup"]; + } + } + + static fromJS(data: any): Word { + data = typeof data === 'object' ? data : {}; + let result = new Word(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["Text"] = this.text; + data["Occurrences"] = this.occurrences; + data["Stem"] = this.stem; + data["IsWordGroup"] = this.isWordGroup; + return data; + } +} + +export interface IWord { + text?: string | undefined; + occurrences?: number | undefined; + stem?: string | undefined; + isWordGroup?: boolean | undefined; +} + +export class SampleOperationParameters extends DistOperationParameters implements ISampleOperationParameters { + numSamples?: number | undefined; + attributeParameters?: AttributeParameters[] | undefined; + brushes?: string[] | undefined; + + constructor(data?: ISampleOperationParameters) { + super(data); + this._discriminator = "SampleOperationParameters"; + } + + init(data?: any) { + super.init(data); + if (data) { + this.numSamples = data["NumSamples"]; + if (data["AttributeParameters"] && data["AttributeParameters"].constructor === Array) { + this.attributeParameters = []; + for (let item of data["AttributeParameters"]) + this.attributeParameters.push(AttributeParameters.fromJS(item)); + } + if (data["Brushes"] && data["Brushes"].constructor === Array) { + this.brushes = []; + for (let item of data["Brushes"]) + this.brushes.push(item); + } + } + } + + static fromJS(data: any): SampleOperationParameters { + data = typeof data === 'object' ? data : {}; + let result = new SampleOperationParameters(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["NumSamples"] = this.numSamples; + if (this.attributeParameters && this.attributeParameters.constructor === Array) { + data["AttributeParameters"] = []; + for (let item of this.attributeParameters) + data["AttributeParameters"].push(item.toJSON()); + } + if (this.brushes && this.brushes.constructor === Array) { + data["Brushes"] = []; + for (let item of this.brushes) + data["Brushes"].push(item); + } + super.toJSON(data); + return data; + } +} + +export interface ISampleOperationParameters extends IDistOperationParameters { + numSamples?: number | undefined; + attributeParameters?: AttributeParameters[] | undefined; + brushes?: string[] | undefined; +} + +export class SampleResult extends DistResult implements ISampleResult { + samples?: { [key: string]: { [key: string]: number; }; } | undefined; + isTruncated?: boolean | undefined; + + constructor(data?: ISampleResult) { + super(data); + this._discriminator = "SampleResult"; + } + + init(data?: any) { + super.init(data); + if (data) { + if (data["Samples"]) { + this.samples = {}; + for (let key in data["Samples"]) { + if (data["Samples"].hasOwnProperty(key)) + this.samples[key] = data["Samples"][key] !== undefined ? data["Samples"][key] : {}; + } + } + this.isTruncated = data["IsTruncated"]; + } + } + + static fromJS(data: any): SampleResult { + data = typeof data === 'object' ? data : {}; + let result = new SampleResult(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + if (this.samples) { + data["Samples"] = {}; + for (let key in this.samples) { + if (this.samples.hasOwnProperty(key)) + data["Samples"][key] = this.samples[key]; + } + } + data["IsTruncated"] = this.isTruncated; + super.toJSON(data); + return data; + } +} + +export interface ISampleResult extends IDistResult { + samples?: { [key: string]: { [key: string]: number; }; } | undefined; + isTruncated?: boolean | undefined; +} + +export class ResultParameters extends UniqueJson implements IResultParameters { + operationReference?: IOperationReference | undefined; + stopOperation?: boolean | undefined; + + protected _discriminator: string; + + constructor(data?: IResultParameters) { + super(data); + this._discriminator = "ResultParameters"; + } + + init(data?: any) { + super.init(data); + if (data) { + this.operationReference = data["OperationReference"] ? IOperationReference.fromJS(data["OperationReference"]) : undefined; + this.stopOperation = data["StopOperation"]; + } + } + + static fromJS(data: any): ResultParameters { + data = typeof data === 'object' ? data : {}; + if (data["discriminator"] === "RecommenderResultParameters") { + let result = new RecommenderResultParameters(); + result.init(data); + return result; + } + let result = new ResultParameters(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["discriminator"] = this._discriminator; + data["OperationReference"] = this.operationReference ? this.operationReference.toJSON() : undefined; + data["StopOperation"] = this.stopOperation; + super.toJSON(data); + return data; + } +} + +export interface IResultParameters extends IUniqueJson { + operationReference?: IOperationReference | undefined; + stopOperation?: boolean | undefined; +} + +export class RecommenderResultParameters extends ResultParameters implements IRecommenderResultParameters { + from?: number | undefined; + to?: number | undefined; + pValueSorting?: Sorting | undefined; + effectSizeFilter?: EffectSize | undefined; + + constructor(data?: IRecommenderResultParameters) { + super(data); + this._discriminator = "RecommenderResultParameters"; + } + + init(data?: any) { + super.init(data); + if (data) { + this.from = data["From"]; + this.to = data["To"]; + this.pValueSorting = data["PValueSorting"]; + this.effectSizeFilter = data["EffectSizeFilter"]; + } + } + + static fromJS(data: any): RecommenderResultParameters { + data = typeof data === 'object' ? data : {}; + let result = new RecommenderResultParameters(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["From"] = this.from; + data["To"] = this.to; + data["PValueSorting"] = this.pValueSorting; + data["EffectSizeFilter"] = this.effectSizeFilter; + super.toJSON(data); + return data; + } +} + +export interface IRecommenderResultParameters extends IResultParameters { + from?: number | undefined; + to?: number | undefined; + pValueSorting?: Sorting | undefined; + effectSizeFilter?: EffectSize | undefined; +} + +export enum Sorting { + Ascending = "Ascending", + Descending = "Descending", +} + +export class AddComparisonParameters extends ModelOperationParameters implements IAddComparisonParameters { + modelId?: ModelId | undefined; + comparisonOrder?: number | undefined; + childOperationParameters?: OperationParameters[] | undefined; + isCachable?: boolean | undefined; + + constructor(data?: IAddComparisonParameters) { + super(data); + this._discriminator = "AddComparisonParameters"; + } + + init(data?: any) { + super.init(data); + if (data) { + this.modelId = data["ModelId"] ? ModelId.fromJS(data["ModelId"]) : undefined; + this.comparisonOrder = data["ComparisonOrder"]; + if (data["ChildOperationParameters"] && data["ChildOperationParameters"].constructor === Array) { + this.childOperationParameters = []; + for (let item of data["ChildOperationParameters"]) + this.childOperationParameters.push(OperationParameters.fromJS(item)); + } + this.isCachable = data["IsCachable"]; + } + } + + static fromJS(data: any): AddComparisonParameters { + data = typeof data === 'object' ? data : {}; + let result = new AddComparisonParameters(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["ModelId"] = this.modelId ? this.modelId.toJSON() : undefined; + data["ComparisonOrder"] = this.comparisonOrder; + if (this.childOperationParameters && this.childOperationParameters.constructor === Array) { + data["ChildOperationParameters"] = []; + for (let item of this.childOperationParameters) + data["ChildOperationParameters"].push(item.toJSON()); + } + data["IsCachable"] = this.isCachable; + super.toJSON(data); + return data; + } +} + +export interface IAddComparisonParameters extends IModelOperationParameters { + modelId?: ModelId | undefined; + comparisonOrder?: number | undefined; + childOperationParameters?: OperationParameters[] | undefined; + isCachable?: boolean | undefined; +} + +export class CDFResult extends DistResult implements ICDFResult { + cDF?: { [key: string]: number; } | undefined; + + constructor(data?: ICDFResult) { + super(data); + this._discriminator = "CDFResult"; + } + + init(data?: any) { + super.init(data); + if (data) { + if (data["CDF"]) { + this.cDF = {}; + for (let key in data["CDF"]) { + if (data["CDF"].hasOwnProperty(key)) + this.cDF[key] = data["CDF"][key]; + } + } + } + } + + static fromJS(data: any): CDFResult { + data = typeof data === 'object' ? data : {}; + let result = new CDFResult(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + if (this.cDF) { + data["CDF"] = {}; + for (let key in this.cDF) { + if (this.cDF.hasOwnProperty(key)) + data["CDF"][key] = this.cDF[key]; + } + } + super.toJSON(data); + return data; + } +} + +export interface ICDFResult extends IDistResult { + cDF?: { [key: string]: number; } | undefined; +} + +export class ChiSquaredTestResult extends HypothesisTestResult implements IChiSquaredTestResult { + hs_aligned?: TupleOfDoubleAndDouble[] | undefined; + + constructor(data?: IChiSquaredTestResult) { + super(data); + this._discriminator = "ChiSquaredTestResult"; + } + + init(data?: any) { + super.init(data); + if (data) { + if (data["hs_aligned"] && data["hs_aligned"].constructor === Array) { + this.hs_aligned = []; + for (let item of data["hs_aligned"]) + this.hs_aligned.push(TupleOfDoubleAndDouble.fromJS(item)); + } + } + } + + static fromJS(data: any): ChiSquaredTestResult { + data = typeof data === 'object' ? data : {}; + let result = new ChiSquaredTestResult(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + if (this.hs_aligned && this.hs_aligned.constructor === Array) { + data["hs_aligned"] = []; + for (let item of this.hs_aligned) + data["hs_aligned"].push(item.toJSON()); + } + super.toJSON(data); + return data; + } +} + +export interface IChiSquaredTestResult extends IHypothesisTestResult { + hs_aligned?: TupleOfDoubleAndDouble[] | undefined; +} + +export class CorrelationTestResult extends HypothesisTestResult implements ICorrelationTestResult { + degreeOfFreedom?: number | undefined; + sampleCorrelationCoefficient?: number | undefined; + distResult?: EmpiricalDistResult | undefined; + + constructor(data?: ICorrelationTestResult) { + super(data); + this._discriminator = "CorrelationTestResult"; + } + + init(data?: any) { + super.init(data); + if (data) { + this.degreeOfFreedom = data["DegreeOfFreedom"]; + this.sampleCorrelationCoefficient = data["SampleCorrelationCoefficient"]; + this.distResult = data["DistResult"] ? EmpiricalDistResult.fromJS(data["DistResult"]) : undefined; + } + } + + static fromJS(data: any): CorrelationTestResult { + data = typeof data === 'object' ? data : {}; + let result = new CorrelationTestResult(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["DegreeOfFreedom"] = this.degreeOfFreedom; + data["SampleCorrelationCoefficient"] = this.sampleCorrelationCoefficient; + data["DistResult"] = this.distResult ? this.distResult.toJSON() : undefined; + super.toJSON(data); + return data; + } +} + +export interface ICorrelationTestResult extends IHypothesisTestResult { + degreeOfFreedom?: number | undefined; + sampleCorrelationCoefficient?: number | undefined; + distResult?: EmpiricalDistResult | undefined; +} + +export class EmpiricalDistResult extends DistResult implements IEmpiricalDistResult { + marginals?: AttributeParameters[] | undefined; + marginalDistParameters?: { [key: string]: DistParameter; } | undefined; + jointDistParameter?: JointDistParameter | undefined; + + constructor(data?: IEmpiricalDistResult) { + super(data); + this._discriminator = "EmpiricalDistResult"; + } + + init(data?: any) { + super.init(data); + if (data) { + if (data["Marginals"] && data["Marginals"].constructor === Array) { + this.marginals = []; + for (let item of data["Marginals"]) + this.marginals.push(AttributeParameters.fromJS(item)); + } + if (data["MarginalDistParameters"]) { + this.marginalDistParameters = {}; + for (let key in data["MarginalDistParameters"]) { + if (data["MarginalDistParameters"].hasOwnProperty(key)) + this.marginalDistParameters[key] = data["MarginalDistParameters"][key] ? DistParameter.fromJS(data["MarginalDistParameters"][key]) : new DistParameter(); + } + } + this.jointDistParameter = data["JointDistParameter"] ? JointDistParameter.fromJS(data["JointDistParameter"]) : undefined; + } + } + + static fromJS(data: any): EmpiricalDistResult { + data = typeof data === 'object' ? data : {}; + let result = new EmpiricalDistResult(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + if (this.marginals && this.marginals.constructor === Array) { + data["Marginals"] = []; + for (let item of this.marginals) + data["Marginals"].push(item.toJSON()); + } + if (this.marginalDistParameters) { + data["MarginalDistParameters"] = {}; + for (let key in this.marginalDistParameters) { + if (this.marginalDistParameters.hasOwnProperty(key)) + data["MarginalDistParameters"][key] = this.marginalDistParameters[key]; + } + } + data["JointDistParameter"] = this.jointDistParameter ? this.jointDistParameter.toJSON() : undefined; + super.toJSON(data); + return data; + } +} + +export interface IEmpiricalDistResult extends IDistResult { + marginals?: AttributeParameters[] | undefined; + marginalDistParameters?: { [key: string]: DistParameter; } | undefined; + jointDistParameter?: JointDistParameter | undefined; +} + +export class DistParameter implements IDistParameter { + mean?: number | undefined; + moment2?: number | undefined; + variance?: number | undefined; + varianceEstimate?: number | undefined; + min?: number | undefined; + max?: number | undefined; + + constructor(data?: IDistParameter) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(data?: any) { + if (data) { + this.mean = data["Mean"]; + this.moment2 = data["Moment2"]; + this.variance = data["Variance"]; + this.varianceEstimate = data["VarianceEstimate"]; + this.min = data["Min"]; + this.max = data["Max"]; + } + } + + static fromJS(data: any): DistParameter { + data = typeof data === 'object' ? data : {}; + let result = new DistParameter(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["Mean"] = this.mean; + data["Moment2"] = this.moment2; + data["Variance"] = this.variance; + data["VarianceEstimate"] = this.varianceEstimate; + data["Min"] = this.min; + data["Max"] = this.max; + return data; + } +} + +export interface IDistParameter { + mean?: number | undefined; + moment2?: number | undefined; + variance?: number | undefined; + varianceEstimate?: number | undefined; + min?: number | undefined; + max?: number | undefined; +} + +export class JointDistParameter implements IJointDistParameter { + jointDist?: DistParameter | undefined; + covariance?: number | undefined; + + constructor(data?: IJointDistParameter) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(data?: any) { + if (data) { + this.jointDist = data["JointDist"] ? DistParameter.fromJS(data["JointDist"]) : undefined; + this.covariance = data["Covariance"]; + } + } + + static fromJS(data: any): JointDistParameter { + data = typeof data === 'object' ? data : {}; + let result = new JointDistParameter(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["JointDist"] = this.jointDist ? this.jointDist.toJSON() : undefined; + data["Covariance"] = this.covariance; + return data; + } +} + +export interface IJointDistParameter { + jointDist?: DistParameter | undefined; + covariance?: number | undefined; +} + +export enum DistributionType { + Continuous = 0, + Discrete = 1, +} + +export abstract class DistributionTypeExtension implements IDistributionTypeExtension { + + constructor(data?: IDistributionTypeExtension) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(data?: any) { + if (data) { + } + } + + static fromJS(data: any): DistributionTypeExtension { + data = typeof data === 'object' ? data : {}; + throw new Error("The abstract class 'DistributionTypeExtension' cannot be instantiated."); + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + return data; + } +} + +export interface IDistributionTypeExtension { +} + +export class GetModelStateParameters extends ModelOperationParameters implements IGetModelStateParameters { + modelId?: ModelId | undefined; + comparisonIds?: ComparisonId[] | undefined; + riskControlType?: RiskControlType | undefined; + + constructor(data?: IGetModelStateParameters) { + super(data); + this._discriminator = "GetModelStateParameters"; + } + + init(data?: any) { + super.init(data); + if (data) { + this.modelId = data["ModelId"] ? ModelId.fromJS(data["ModelId"]) : undefined; + if (data["ComparisonIds"] && data["ComparisonIds"].constructor === Array) { + this.comparisonIds = []; + for (let item of data["ComparisonIds"]) + this.comparisonIds.push(ComparisonId.fromJS(item)); + } + this.riskControlType = data["RiskControlType"]; + } + } + + static fromJS(data: any): GetModelStateParameters { + data = typeof data === 'object' ? data : {}; + let result = new GetModelStateParameters(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["ModelId"] = this.modelId ? this.modelId.toJSON() : undefined; + if (this.comparisonIds && this.comparisonIds.constructor === Array) { + data["ComparisonIds"] = []; + for (let item of this.comparisonIds) + data["ComparisonIds"].push(item.toJSON()); + } + data["RiskControlType"] = this.riskControlType; + super.toJSON(data); + return data; + } +} + +export interface IGetModelStateParameters extends IModelOperationParameters { + modelId?: ModelId | undefined; + comparisonIds?: ComparisonId[] | undefined; + riskControlType?: RiskControlType | undefined; +} + +export class KSTestResult extends HypothesisTestResult implements IKSTestResult { + + constructor(data?: IKSTestResult) { + super(data); + this._discriminator = "KSTestResult"; + } + + init(data?: any) { + super.init(data); + if (data) { + } + } + + static fromJS(data: any): KSTestResult { + data = typeof data === 'object' ? data : {}; + let result = new KSTestResult(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + super.toJSON(data); + return data; + } +} + +export interface IKSTestResult extends IHypothesisTestResult { +} + +export class ModelWealthParameters extends UniqueJson implements IModelWealthParameters { + modelId?: ModelId | undefined; + riskControlType?: RiskControlType | undefined; + + constructor(data?: IModelWealthParameters) { + super(data); + } + + init(data?: any) { + super.init(data); + if (data) { + this.modelId = data["ModelId"] ? ModelId.fromJS(data["ModelId"]) : undefined; + this.riskControlType = data["RiskControlType"]; + } + } + + static fromJS(data: any): ModelWealthParameters { + data = typeof data === 'object' ? data : {}; + let result = new ModelWealthParameters(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["ModelId"] = this.modelId ? this.modelId.toJSON() : undefined; + data["RiskControlType"] = this.riskControlType; + super.toJSON(data); + return data; + } +} + +export interface IModelWealthParameters extends IUniqueJson { + modelId?: ModelId | undefined; + riskControlType?: RiskControlType | undefined; +} + +export class RootMeanSquareTestResult extends HypothesisTestResult implements IRootMeanSquareTestResult { + simulationCount?: number | undefined; + extremeSimulationCount?: number | undefined; + + constructor(data?: IRootMeanSquareTestResult) { + super(data); + this._discriminator = "RootMeanSquareTestResult"; + } + + init(data?: any) { + super.init(data); + if (data) { + this.simulationCount = data["SimulationCount"]; + this.extremeSimulationCount = data["ExtremeSimulationCount"]; + } + } + + static fromJS(data: any): RootMeanSquareTestResult { + data = typeof data === 'object' ? data : {}; + let result = new RootMeanSquareTestResult(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["SimulationCount"] = this.simulationCount; + data["ExtremeSimulationCount"] = this.extremeSimulationCount; + super.toJSON(data); + return data; + } +} + +export interface IRootMeanSquareTestResult extends IHypothesisTestResult { + simulationCount?: number | undefined; + extremeSimulationCount?: number | undefined; +} + +export class TTestResult extends HypothesisTestResult implements ITTestResult { + degreeOfFreedom?: number | undefined; + distResults?: EmpiricalDistResult[] | undefined; + + constructor(data?: ITTestResult) { + super(data); + this._discriminator = "TTestResult"; + } + + init(data?: any) { + super.init(data); + if (data) { + this.degreeOfFreedom = data["DegreeOfFreedom"]; + if (data["DistResults"] && data["DistResults"].constructor === Array) { + this.distResults = []; + for (let item of data["DistResults"]) + this.distResults.push(EmpiricalDistResult.fromJS(item)); + } + } + } + + static fromJS(data: any): TTestResult { + data = typeof data === 'object' ? data : {}; + let result = new TTestResult(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["DegreeOfFreedom"] = this.degreeOfFreedom; + if (this.distResults && this.distResults.constructor === Array) { + data["DistResults"] = []; + for (let item of this.distResults) + data["DistResults"].push(item.toJSON()); + } + super.toJSON(data); + return data; + } +} + +export interface ITTestResult extends IHypothesisTestResult { + degreeOfFreedom?: number | undefined; + distResults?: EmpiricalDistResult[] | undefined; +} + +export enum Sorting2 { + Ascending = 0, + Descending = 1, +} + +export class BinLabel implements IBinLabel { + value?: number | undefined; + minValue?: number | undefined; + maxValue?: number | undefined; + label?: string | undefined; + + constructor(data?: IBinLabel) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(data?: any) { + if (data) { + this.value = data["Value"]; + this.minValue = data["MinValue"]; + this.maxValue = data["MaxValue"]; + this.label = data["Label"]; + } + } + + static fromJS(data: any): BinLabel { + data = typeof data === 'object' ? data : {}; + let result = new BinLabel(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["Value"] = this.value; + data["MinValue"] = this.minValue; + data["MaxValue"] = this.maxValue; + data["Label"] = this.label; + return data; + } +} + +export interface IBinLabel { + value?: number | undefined; + minValue?: number | undefined; + maxValue?: number | undefined; + label?: string | undefined; +} + +export class PreProcessedString implements IPreProcessedString { + value?: string | undefined; + id?: number | undefined; + stringLookup?: { [key: string]: number; } | undefined; + indexLookup?: { [key: string]: string; } | undefined; + + constructor(data?: IPreProcessedString) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(data?: any) { + if (data) { + this.value = data["Value"]; + this.id = data["Id"]; + if (data["StringLookup"]) { + this.stringLookup = {}; + for (let key in data["StringLookup"]) { + if (data["StringLookup"].hasOwnProperty(key)) + this.stringLookup[key] = data["StringLookup"][key]; + } + } + if (data["IndexLookup"]) { + this.indexLookup = {}; + for (let key in data["IndexLookup"]) { + if (data["IndexLookup"].hasOwnProperty(key)) + this.indexLookup[key] = data["IndexLookup"][key]; + } + } + } + } + + static fromJS(data: any): PreProcessedString { + data = typeof data === 'object' ? data : {}; + let result = new PreProcessedString(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["Value"] = this.value; + data["Id"] = this.id; + if (this.stringLookup) { + data["StringLookup"] = {}; + for (let key in this.stringLookup) { + if (this.stringLookup.hasOwnProperty(key)) + data["StringLookup"][key] = this.stringLookup[key]; + } + } + if (this.indexLookup) { + data["IndexLookup"] = {}; + for (let key in this.indexLookup) { + if (this.indexLookup.hasOwnProperty(key)) + data["IndexLookup"][key] = this.indexLookup[key]; + } + } + return data; + } +} + +export interface IPreProcessedString { + value?: string | undefined; + id?: number | undefined; + stringLookup?: { [key: string]: number; } | undefined; + indexLookup?: { [key: string]: string; } | undefined; +} + +export class BitSet implements IBitSet { + length?: number | undefined; + size?: number | undefined; + + constructor(data?: IBitSet) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(data?: any) { + if (data) { + this.length = data["Length"]; + this.size = data["Size"]; + } + } + + static fromJS(data: any): BitSet { + data = typeof data === 'object' ? data : {}; + let result = new BitSet(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["Length"] = this.length; + data["Size"] = this.size; + return data; + } +} + +export interface IBitSet { + length?: number | undefined; + size?: number | undefined; +} + +export class DateTimeUtil implements IDateTimeUtil { + + constructor(data?: IDateTimeUtil) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(data?: any) { + if (data) { + } + } + + static fromJS(data: any): DateTimeUtil { + data = typeof data === 'object' ? data : {}; + let result = new DateTimeUtil(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + return data; + } +} + +export interface IDateTimeUtil { +} + +export class FrequentItemsetOperationParameters extends DistOperationParameters implements IFrequentItemsetOperationParameters { + filter?: string | undefined; + attributeParameters?: AttributeParameters[] | undefined; + attributeCodeParameters?: AttributeCaclculatedParameters[] | undefined; + + constructor(data?: IFrequentItemsetOperationParameters) { + super(data); + this._discriminator = "FrequentItemsetOperationParameters"; + } + + init(data?: any) { + super.init(data); + if (data) { + this.filter = data["Filter"]; + if (data["AttributeParameters"] && data["AttributeParameters"].constructor === Array) { + this.attributeParameters = []; + for (let item of data["AttributeParameters"]) + this.attributeParameters.push(AttributeParameters.fromJS(item)); + } + if (data["AttributeCodeParameters"] && data["AttributeCodeParameters"].constructor === Array) { + this.attributeCodeParameters = []; + for (let item of data["AttributeCodeParameters"]) + this.attributeCodeParameters.push(AttributeCaclculatedParameters.fromJS(item)); + } + } + } + + static fromJS(data: any): FrequentItemsetOperationParameters { + data = typeof data === 'object' ? data : {}; + let result = new FrequentItemsetOperationParameters(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["Filter"] = this.filter; + if (this.attributeParameters && this.attributeParameters.constructor === Array) { + data["AttributeParameters"] = []; + for (let item of this.attributeParameters) + data["AttributeParameters"].push(item.toJSON()); + } + if (this.attributeCodeParameters && this.attributeCodeParameters.constructor === Array) { + data["AttributeCodeParameters"] = []; + for (let item of this.attributeCodeParameters) + data["AttributeCodeParameters"].push(item.toJSON()); + } + super.toJSON(data); + return data; + } +} + +export interface IFrequentItemsetOperationParameters extends IDistOperationParameters { + filter?: string | undefined; + attributeParameters?: AttributeParameters[] | undefined; + attributeCodeParameters?: AttributeCaclculatedParameters[] | undefined; +} + +export class FrequentItemsetResult extends Result implements IFrequentItemsetResult { + frequentItems?: { [key: string]: number; } | undefined; + + constructor(data?: IFrequentItemsetResult) { + super(data); + this._discriminator = "FrequentItemsetResult"; + } + + init(data?: any) { + super.init(data); + if (data) { + if (data["FrequentItems"]) { + this.frequentItems = {}; + for (let key in data["FrequentItems"]) { + if (data["FrequentItems"].hasOwnProperty(key)) + this.frequentItems[key] = data["FrequentItems"][key]; + } + } + } + } + + static fromJS(data: any): FrequentItemsetResult { + data = typeof data === 'object' ? data : {}; + let result = new FrequentItemsetResult(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + if (this.frequentItems) { + data["FrequentItems"] = {}; + for (let key in this.frequentItems) { + if (this.frequentItems.hasOwnProperty(key)) + data["FrequentItems"][key] = this.frequentItems[key]; + } + } + super.toJSON(data); + return data; + } +} + +export interface IFrequentItemsetResult extends IResult { + frequentItems?: { [key: string]: number; } | undefined; +} + -- cgit v1.2.3-70-g09d2 From a16e6592caafb601b59c3d9f7609e8c1af231eba Mon Sep 17 00:00:00 2001 From: bob Date: Wed, 20 Mar 2019 18:00:39 -0400 Subject: initial --- package.json | 2 + src/client/documents/Documents.ts | 14 +- src/client/northstar/core/BaseObject.ts | 12 ++ .../northstar/core/attribute/AttributeModel.ts | 111 ++++++++++ .../core/attribute/AttributeTransformationModel.ts | 47 ++++ .../core/attribute/CalculatedAttributeModel.ts | 42 ++++ .../northstar/core/brusher/BrushLinkModel.ts | 40 ++++ .../northstar/core/brusher/IBaseBrushable.ts | 13 ++ src/client/northstar/core/brusher/IBaseBrusher.ts | 11 + src/client/northstar/core/filter/FilterModel.ts | 81 +++++++ src/client/northstar/core/filter/FilterOperand.ts | 5 + src/client/northstar/core/filter/FilterType.ts | 6 + .../northstar/core/filter/IBaseFilterConsumer.ts | 10 + .../northstar/core/filter/IBaseFilterProvider.ts | 8 + .../northstar/core/filter/ValueComparision.ts | 74 +++++++ src/client/northstar/model/ModelExtensions.ts | 48 +++++ src/client/northstar/model/ModelHelpers.ts | 215 +++++++++++++++++++ .../model/binRanges/AlphabeticVisualBinRange.ts | 52 +++++ .../model/binRanges/DateTimeVisualBinRange.ts | 105 +++++++++ .../model/binRanges/NominalVisualBinRange.ts | 52 +++++ .../model/binRanges/QuantitativeVisualBinRange.ts | 90 ++++++++ .../northstar/model/binRanges/VisualBinRange.ts | 36 ++++ .../model/binRanges/VisualBinRangeHelper.ts | 71 +++++++ src/client/northstar/operations/BaseOperation.ts | 174 +++++++++++++++ .../northstar/operations/HistogramOperation.ts | 111 ++++++++++ src/client/northstar/utils/ArrayUtil.ts | 90 ++++++++ src/client/northstar/utils/Extensions.ts | 20 ++ src/client/northstar/utils/GeometryUtil.ts | 129 +++++++++++ src/client/northstar/utils/IDisposable.ts | 3 + src/client/northstar/utils/IEquatable.ts | 3 + src/client/northstar/utils/KeyCodes.ts | 137 ++++++++++++ src/client/northstar/utils/MathUtil.ts | 236 +++++++++++++++++++++ src/client/northstar/utils/PartialClass.ts | 7 + src/client/northstar/utils/Utils.ts | 75 +++++++ src/client/views/Main.tsx | 47 +++- src/client/views/nodes/DocumentContentsView.tsx | 4 +- src/client/views/nodes/FieldView.tsx | 7 +- src/client/views/nodes/HistogramBox.scss | 8 + src/client/views/nodes/HistogramBox.tsx | 67 ++++++ src/fields/KeyStore.ts | 1 + 40 files changed, 2250 insertions(+), 14 deletions(-) create mode 100644 src/client/northstar/core/BaseObject.ts create mode 100644 src/client/northstar/core/attribute/AttributeModel.ts create mode 100644 src/client/northstar/core/attribute/AttributeTransformationModel.ts create mode 100644 src/client/northstar/core/attribute/CalculatedAttributeModel.ts create mode 100644 src/client/northstar/core/brusher/BrushLinkModel.ts create mode 100644 src/client/northstar/core/brusher/IBaseBrushable.ts create mode 100644 src/client/northstar/core/brusher/IBaseBrusher.ts create mode 100644 src/client/northstar/core/filter/FilterModel.ts create mode 100644 src/client/northstar/core/filter/FilterOperand.ts create mode 100644 src/client/northstar/core/filter/FilterType.ts create mode 100644 src/client/northstar/core/filter/IBaseFilterConsumer.ts create mode 100644 src/client/northstar/core/filter/IBaseFilterProvider.ts create mode 100644 src/client/northstar/core/filter/ValueComparision.ts create mode 100644 src/client/northstar/model/ModelExtensions.ts create mode 100644 src/client/northstar/model/ModelHelpers.ts create mode 100644 src/client/northstar/model/binRanges/AlphabeticVisualBinRange.ts create mode 100644 src/client/northstar/model/binRanges/DateTimeVisualBinRange.ts create mode 100644 src/client/northstar/model/binRanges/NominalVisualBinRange.ts create mode 100644 src/client/northstar/model/binRanges/QuantitativeVisualBinRange.ts create mode 100644 src/client/northstar/model/binRanges/VisualBinRange.ts create mode 100644 src/client/northstar/model/binRanges/VisualBinRangeHelper.ts create mode 100644 src/client/northstar/operations/BaseOperation.ts create mode 100644 src/client/northstar/operations/HistogramOperation.ts create mode 100644 src/client/northstar/utils/ArrayUtil.ts create mode 100644 src/client/northstar/utils/Extensions.ts create mode 100644 src/client/northstar/utils/GeometryUtil.ts create mode 100644 src/client/northstar/utils/IDisposable.ts create mode 100644 src/client/northstar/utils/IEquatable.ts create mode 100644 src/client/northstar/utils/KeyCodes.ts create mode 100644 src/client/northstar/utils/MathUtil.ts create mode 100644 src/client/northstar/utils/PartialClass.ts create mode 100644 src/client/northstar/utils/Utils.ts create mode 100644 src/client/views/nodes/HistogramBox.scss create mode 100644 src/client/views/nodes/HistogramBox.tsx (limited to 'src/client/northstar') diff --git a/package.json b/package.json index c87e31bc4..33333a402 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,7 @@ "@types/connect-flash": "0.0.34", "@types/cookie-parser": "^1.4.1", "@types/cookie-session": "^2.0.36", + "@types/d3-format": "^1.3.1", "@types/express": "^4.16.1", "@types/express-flash": "0.0.0", "@types/express-session": "^1.15.12", @@ -93,6 +94,7 @@ "cookie-parser": "^1.4.4", "cookie-session": "^2.0.0-beta.3", "crypto-browserify": "^3.11.0", + "d3-format": "^1.3.2", "express": "^4.16.4", "express-flash": "0.0.2", "express-session": "^1.15.6", diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 4ed1fc3ed..b1e1f8c7b 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -22,6 +22,7 @@ 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"; export interface DocumentOptions { x?: number; @@ -44,6 +45,7 @@ export interface DocumentOptions { export namespace Documents { let textProto: Document; + let histoProto: Document; let imageProto: Document; let webProto: Document; let collProto: Document; @@ -52,6 +54,7 @@ export namespace Documents { let audioProto: Document; let pdfProto: Document; const textProtoId = "textProto"; + const histoProtoId = "histoProto"; const pdfProtoId = "pdfProto"; const imageProtoId = "imageProto"; const webProtoId = "webProto"; @@ -62,9 +65,10 @@ export namespace Documents { export function initProtos(callback: () => void) { Server.GetFields([collProtoId, textProtoId, imageProtoId], (fields) => { + textProto = fields[textProtoId] as Document; + histoProto = fields[histoProtoId] as Document; collProto = fields[collProtoId] as Document; imageProto = fields[imageProtoId] as Document; - textProto = fields[textProtoId] as Document; webProto = fields[webProtoId] as Document; kvpProto = fields[kvpProtoId] as Document; callback(); @@ -114,6 +118,11 @@ export namespace Documents { } return imageProto; } + function GetHistogramPrototype(): Document { + return histoProto ? histoProto : + histoProto = setupPrototypeOptions(textProtoId, "HISTO PROTOTYPE", HistogramBox.LayoutString(), + { x: 0, y: 0, width: 300, height: 300, layoutKeys: [KeyStore.Data] }); + } function GetTextPrototype(): Document { return textProto ? textProto : textProto = setupPrototypeOptions(textProtoId, "TEXT_PROTO", FormattedTextBox.LayoutString(), @@ -176,6 +185,9 @@ 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 TextDocument(options: DocumentOptions = {}) { return assignToDelegate(SetInstanceOptions(GetTextPrototype(), options, ["", TextField]).MakeDelegate(), options); } diff --git a/src/client/northstar/core/BaseObject.ts b/src/client/northstar/core/BaseObject.ts new file mode 100644 index 000000000..e9e766e31 --- /dev/null +++ b/src/client/northstar/core/BaseObject.ts @@ -0,0 +1,12 @@ +import { IEquatable } from '../utils/IEquatable' +import { IDisposable } from '../utils/IDisposable' + +export class BaseObject implements IEquatable, IDisposable { + + public Equals(other: Object): boolean { + return this == other; + } + + public Dispose(): void { + } +} \ No newline at end of file diff --git a/src/client/northstar/core/attribute/AttributeModel.ts b/src/client/northstar/core/attribute/AttributeModel.ts new file mode 100644 index 000000000..124a5b45a --- /dev/null +++ b/src/client/northstar/core/attribute/AttributeModel.ts @@ -0,0 +1,111 @@ +import { Attribute, DataType, VisualizationHint } from '../../model/idea/idea' +import { BaseObject } from '../BaseObject' +import { observable } from "mobx"; + +export abstract class AttributeModel extends BaseObject { + public abstract get DisplayName(): string; + public abstract get CodeName(): string; + public abstract get DataType(): DataType; + public abstract get VisualizationHints(): VisualizationHint[]; +} + +export class ColumnAttributeModel extends AttributeModel { + public Attribute: Attribute; + + constructor(attribute: Attribute) { + super(); + this.Attribute = attribute; + } + + public get DataType(): DataType { + return this.Attribute.dataType ? this.Attribute.dataType : DataType.Undefined; + } + + public get DisplayName(): string { + return this.Attribute.displayName ? this.Attribute.displayName.ReplaceAll("_", " ") : ""; + } + + public get CodeName(): string { + return this.Attribute.rawName ? this.Attribute.rawName : ""; + } + + public get VisualizationHints(): VisualizationHint[] { + return this.Attribute.visualizationHints ? this.Attribute.visualizationHints : []; + } + + public Equals(other: ColumnAttributeModel): boolean { + return this.Attribute.rawName == other.Attribute.rawName; + } +} + +export class CodeAttributeModel extends AttributeModel { + private _visualizationHints: VisualizationHint[]; + + public CodeName: string; + + @observable + public Code: string; + + constructor(code: string, codeName: string, displayName: string, visualizationHints: VisualizationHint[]) { + super(); + this.Code = code; + this.CodeName = codeName; + this.DisplayName = displayName; + this._visualizationHints = visualizationHints; + } + + public get DataType(): DataType { + return DataType.Undefined; + } + + @observable + public DisplayName: string; + + public get VisualizationHints(): VisualizationHint[] { + return this._visualizationHints; + } + + public Equals(other: CodeAttributeModel): boolean { + return this.CodeName === other.CodeName; + } + +} + +export class BackendAttributeModel extends AttributeModel { + private _dataType: DataType; + private _displayName: string; + private _codeName: string; + private _visualizationHints: VisualizationHint[]; + + public Id: string; + + constructor(id: string, dataType: DataType, displayName: string, codeName: string, visualizationHints: VisualizationHint[]) { + super(); + this.Id = id; + this._dataType = dataType; + this._displayName = displayName; + this._codeName = codeName; + this._visualizationHints = visualizationHints; + } + + public get DataType(): DataType { + return this._dataType; + } + + public get DisplayName(): string { + return this._displayName.ReplaceAll("_", " ");; + } + + public get CodeName(): string { + return this._codeName; + } + + public get VisualizationHints(): VisualizationHint[] { + return this._visualizationHints; + } + + public Equals(other: BackendAttributeModel): boolean { + return this.Id == other.Id; + } + +} \ No newline at end of file diff --git a/src/client/northstar/core/attribute/AttributeTransformationModel.ts b/src/client/northstar/core/attribute/AttributeTransformationModel.ts new file mode 100644 index 000000000..cc5aa7154 --- /dev/null +++ b/src/client/northstar/core/attribute/AttributeTransformationModel.ts @@ -0,0 +1,47 @@ +; +import { computed, observable } from "mobx"; +import { AggregateFunction } from "../../model/idea/idea"; +import { AttributeModel } from "./AttributeModel"; +import { IEquatable } from "../../utils/IEquatable"; + +export class AttributeTransformationModel implements IEquatable { + + @observable public AggregateFunction: AggregateFunction; + @observable public AttributeModel: AttributeModel; + + constructor(attributeModel: AttributeModel, aggregateFunction: AggregateFunction = AggregateFunction.None) { + this.AttributeModel = attributeModel; + this.AggregateFunction = aggregateFunction; + } + + @computed + public get PresentedName(): string { + var displayName = this.AttributeModel.DisplayName; + if (this.AggregateFunction === AggregateFunction.Count) { + return "count"; + } + if (this.AggregateFunction === AggregateFunction.Avg) + displayName = "avg(" + displayName + ")"; + else if (this.AggregateFunction === AggregateFunction.Max) + displayName = "max(" + displayName + ")"; + else if (this.AggregateFunction === AggregateFunction.Min) + displayName = "min(" + displayName + ")"; + else if (this.AggregateFunction === AggregateFunction.Sum) + displayName = "sum(" + displayName + ")"; + else if (this.AggregateFunction === AggregateFunction.SumE) + displayName = "sumE(" + displayName + ")"; + + return displayName; + } + + public clone(): AttributeTransformationModel { + var clone = new AttributeTransformationModel(this.AttributeModel); + clone.AggregateFunction = this.AggregateFunction; + return clone; + } + + public Equals(other: AttributeTransformationModel): boolean { + return this.AggregateFunction == other.AggregateFunction && + this.AttributeModel.Equals(other.AttributeModel); + } +} \ No newline at end of file diff --git a/src/client/northstar/core/attribute/CalculatedAttributeModel.ts b/src/client/northstar/core/attribute/CalculatedAttributeModel.ts new file mode 100644 index 000000000..ab96c794d --- /dev/null +++ b/src/client/northstar/core/attribute/CalculatedAttributeModel.ts @@ -0,0 +1,42 @@ +import { BackendAttributeModel, AttributeModel, CodeAttributeModel } from "./AttributeModel"; +import { DataType, VisualizationHint } from '../../model/idea/idea' + +export class CalculatedAttributeManager { + public static AllCalculatedAttributes: Array = new Array(); + + public static Clear() { + this.AllCalculatedAttributes = new Array(); + } + + public static CreateBackendAttributeModel(id: string, dataType: DataType, displayName: string, codeName: string, visualizationHints: VisualizationHint[]): BackendAttributeModel { + var filtered = this.AllCalculatedAttributes.filter(am => { + if (am instanceof BackendAttributeModel && + am.Id == id) { + return true; + } + return false; + }); + if (filtered.length > 0) { + return filtered[0] as BackendAttributeModel; + } + var newAttr = new BackendAttributeModel(id, dataType, displayName, codeName, visualizationHints); + this.AllCalculatedAttributes.push(newAttr); + return newAttr; + } + + public static CreateCodeAttributeModel(code: string, codeName: string, visualizationHints: VisualizationHint[]): CodeAttributeModel { + var filtered = this.AllCalculatedAttributes.filter(am => { + if (am instanceof CodeAttributeModel && + am.CodeName == codeName) { + return true; + } + return false; + }); + if (filtered.length > 0) { + return filtered[0] as CodeAttributeModel; + } + var newAttr = new CodeAttributeModel(code, codeName, codeName.ReplaceAll("_", " "), visualizationHints); + this.AllCalculatedAttributes.push(newAttr); + return newAttr; + } +} \ No newline at end of file diff --git a/src/client/northstar/core/brusher/BrushLinkModel.ts b/src/client/northstar/core/brusher/BrushLinkModel.ts new file mode 100644 index 000000000..e3ac43367 --- /dev/null +++ b/src/client/northstar/core/brusher/BrushLinkModel.ts @@ -0,0 +1,40 @@ +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 new file mode 100644 index 000000000..07d4e7580 --- /dev/null +++ b/src/client/northstar/core/brusher/IBaseBrushable.ts @@ -0,0 +1,13 @@ +import { BrushLinkModel } from '../brusher/BrushLinkModel' +import { PIXIPoint } from '../../utils/MathUtil' +import { IEquatable } from '../../utils/IEquatable'; + +export interface IBaseBrushable extends IEquatable { + BrusherModels: Array>; + BrushColors: Array; + Position: PIXIPoint; + Size: PIXIPoint; +} +export function instanceOfIBaseBrushable(object: any): object is IBaseBrushable { + return 'BrusherModels' in object; +} \ No newline at end of file diff --git a/src/client/northstar/core/brusher/IBaseBrusher.ts b/src/client/northstar/core/brusher/IBaseBrusher.ts new file mode 100644 index 000000000..d7ae65464 --- /dev/null +++ b/src/client/northstar/core/brusher/IBaseBrusher.ts @@ -0,0 +1,11 @@ +import { PIXIPoint } from '../../utils/MathUtil' +import { IEquatable } from '../../utils/IEquatable'; + + +export interface IBaseBrusher extends IEquatable { + Position: PIXIPoint; + Size: PIXIPoint; +} +export function instanceOfIBaseBrusher(object: any): object is IBaseBrusher { + return 'BrushableModels' in object; +} \ No newline at end of file diff --git a/src/client/northstar/core/filter/FilterModel.ts b/src/client/northstar/core/filter/FilterModel.ts new file mode 100644 index 000000000..3c4cfc4a7 --- /dev/null +++ b/src/client/northstar/core/filter/FilterModel.ts @@ -0,0 +1,81 @@ +import { ValueComparison } from "./ValueComparision"; +import { Utils } from "../../utils/Utils"; + +export class FilterModel { + public ValueComparisons: ValueComparison[]; + constructor() { + this.ValueComparisons = new Array(); + } + + public Equals(other: FilterModel): boolean { + if (!Utils.EqualityHelper(this, other)) return false; + if (!this.isSame(this.ValueComparisons, (other as FilterModel).ValueComparisons)) return false; + return true; + } + + private isSame(a: ValueComparison[], b: ValueComparison[]): boolean { + if (a.length !== b.length) { + return false; + } + for (let i = 0; i < a.length; i++) { + let valueComp = a[i]; + if (!valueComp.Equals(b[i])) { + return false; + } + } + return true; + } + + public ToPythonString(): string { + let ret = "(" + this.ValueComparisons.map(vc => vc.ToPythonString()).join("&&") + ")"; + return ret; + } + + public static And(filters: string[]): string { + let ret = filters.filter(f => f !== "").join(" && "); + return ret; + } + + // public static GetFilterModelsRecursive(filterGraphNode: GraphNode, + // 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 (!isFirst && filtered.length > 0) { + // filterModels.push(...filtered); + // ret = "(" + filterGraphNode.Data.FilterModels.filter(fm => fm != null).map(fm => fm.ToPythonString()).join(" || ") + ")"; + // } + // } + // if (Utils.isBaseFilterConsumer(filterGraphNode.Data) && filterGraphNode.Links != null) { + // let children = new Array(); + // let linkedGraphNodes = filterGraphNode.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(filterGraphNode.Data.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/core/filter/FilterOperand.ts b/src/client/northstar/core/filter/FilterOperand.ts new file mode 100644 index 000000000..2e8e8d6a0 --- /dev/null +++ b/src/client/northstar/core/filter/FilterOperand.ts @@ -0,0 +1,5 @@ +export enum FilterOperand +{ + AND, + OR +} \ No newline at end of file diff --git a/src/client/northstar/core/filter/FilterType.ts b/src/client/northstar/core/filter/FilterType.ts new file mode 100644 index 000000000..9adbc087f --- /dev/null +++ b/src/client/northstar/core/filter/FilterType.ts @@ -0,0 +1,6 @@ +export enum FilterType +{ + Filter, + Brush, + Slice +} \ No newline at end of file diff --git a/src/client/northstar/core/filter/IBaseFilterConsumer.ts b/src/client/northstar/core/filter/IBaseFilterConsumer.ts new file mode 100644 index 000000000..e687acb8a --- /dev/null +++ b/src/client/northstar/core/filter/IBaseFilterConsumer.ts @@ -0,0 +1,10 @@ +import { FilterOperand } from '../filter/FilterOperand' +import { IEquatable } from '../../utils/IEquatable' + +export interface IBaseFilterConsumer extends IEquatable { + FilterOperand: FilterOperand; +} + +export function instanceOfIBaseFilterConsumer(object: any): object is IBaseFilterConsumer { + return 'FilterOperand' in object; +} \ No newline at end of file diff --git a/src/client/northstar/core/filter/IBaseFilterProvider.ts b/src/client/northstar/core/filter/IBaseFilterProvider.ts new file mode 100644 index 000000000..d082bfe12 --- /dev/null +++ b/src/client/northstar/core/filter/IBaseFilterProvider.ts @@ -0,0 +1,8 @@ +import { FilterModel } from '../filter/FilterModel' + +export interface IBaseFilterProvider { + FilterModels: Array; +} +export function instanceOfIBaseFilterProvider(object: any): object is IBaseFilterProvider { + return 'FilterModels' in object; +} \ No newline at end of file diff --git a/src/client/northstar/core/filter/ValueComparision.ts b/src/client/northstar/core/filter/ValueComparision.ts new file mode 100644 index 000000000..1e729d06e --- /dev/null +++ b/src/client/northstar/core/filter/ValueComparision.ts @@ -0,0 +1,74 @@ +import { Predicate } from '../../model/idea/idea' +import { Utils } from '../../utils/Utils' +import { AttributeModel } from '../attribute/AttributeModel'; + +export class ValueComparison { + + public attributeModel: AttributeModel; + public Value: any; + public Predicate: Predicate; + + public constructor(attributeModel: AttributeModel, predicate: Predicate, value: any) { + this.attributeModel = attributeModel; + this.Value = value; + this.Predicate = predicate; + } + + public Equals(other: Object): boolean { + if (!Utils.EqualityHelper(this, other)) + return false; + if (this.Predicate !== (other as ValueComparison).Predicate) + return false; + let isComplex = (typeof this.Value === "object"); + if (!isComplex && this.Value != (other as ValueComparison).Value) + return false; + if (isComplex && !this.Value.Equals((other as ValueComparison).Value)) + return false; + return true; + } + + public ToPythonString(): string { + var op = ""; + switch (this.Predicate) { + case Predicate.EQUALS: + op = "=="; + break; + case Predicate.GREATER_THAN: + op = ">"; + break; + case Predicate.GREATER_THAN_EQUAL: + op = ">="; + break; + case Predicate.LESS_THAN: + op = "<"; + break; + case Predicate.LESS_THAN_EQUAL: + op = "<="; + break; + default: + op = "=="; + break; + } + + var val = this.Value.toString(); + if (typeof this.Value === 'string' || this.Value instanceof String) { + val = "\"" + val + "\""; + } + var ret = " "; + var rawName = this.attributeModel.CodeName; + switch (this.Predicate) { + case Predicate.STARTS_WITH: + ret += rawName + " != null && " + rawName + ".StartsWith(" + val + ") "; + return ret; + case Predicate.ENDS_WITH: + ret += rawName + " != null && " + rawName + ".EndsWith(" + val + ") "; + return ret; + case Predicate.CONTAINS: + ret += rawName + " != null && " + rawName + ".Contains(" + val + ") "; + return ret; + default: + ret += rawName + " " + op + " " + val + " "; + return ret; + } + } +} \ No newline at end of file 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 (this).constructor.name === (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): Array { + var aggregateParameters = new Array(); + 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 { + var ret = new Array(); + 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 = [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(); + 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(); + 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 { + var labels = new Array(); + 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(); + 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(); + 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 { + var labels = new Array(); + 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(); + + 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(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; + + public GetLabel(value: number): string { + return value.toString(); + } + + public GetLabels(): Array { + var labels = new Array(); + 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 = 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; + } + } +} 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(); + } +} + + diff --git a/src/client/northstar/utils/ArrayUtil.ts b/src/client/northstar/utils/ArrayUtil.ts new file mode 100644 index 000000000..f35c98317 --- /dev/null +++ b/src/client/northstar/utils/ArrayUtil.ts @@ -0,0 +1,90 @@ +import { Exception } from "../model/idea/idea"; + +export class ArrayUtil { + + public static Contains(arr1: any[], arr2: any): boolean { + if (arr1.length === 0) { + return false; + } + let isComplex = typeof arr1[0] === "object"; + for (let i = 0; i < arr1.length; i++) { + if (isComplex && "Equals" in arr1[i]) { + if (arr1[i].Equals(arr2)) { + return true; + } + } + else { + if (arr1[i] === arr2) { + return true; + } + } + } + return false; + } + + + public static RemoveMany(arr: any[], elements: Object[]) { + elements.forEach(e => ArrayUtil.Remove(arr, e)); + } + + public static AddMany(arr: any[], others: Object[]) { + arr.push(...others); + } + + public static Clear(arr: any[]) { + arr.splice(0, arr.length); + } + + + public static Remove(arr: any[], other: Object) { + const index = ArrayUtil.IndexOfWithEqual(arr, other); + if (index === -1) { + return; + } + arr.splice(index, 1); + } + + + public static First(arr: T[], predicate: (x: any) => boolean): T { + let filtered = arr.filter(predicate); + if (filtered.length > 0) { + return filtered[0]; + } + throw new Exception() + } + + public static FirstOrDefault(arr: T[], predicate: (x: any) => boolean): T | undefined { + let filtered = arr.filter(predicate); + if (filtered.length > 0) { + return filtered[0]; + } + return undefined; + } + + public static Distinct(arr: any[]): any[] { + let ret = []; + for (let i = 0; i < arr.length; i++) { + if (!ArrayUtil.Contains(ret, arr[i])) { + ret.push(arr[i]); + } + } + return ret; + } + + public static IndexOfWithEqual(arr: any[], other: any): number { + for (let i = 0; i < arr.length; i++) { + let isComplex = typeof arr[0] === "object"; + if (isComplex && "Equals" in arr[i]) { + if (arr[i].Equals(other)) { + return i; + } + } + else { + if (arr[i] === other) { + return i; + } + } + } + return -1; + } +} \ No newline at end of file diff --git a/src/client/northstar/utils/Extensions.ts b/src/client/northstar/utils/Extensions.ts new file mode 100644 index 000000000..71bcadf89 --- /dev/null +++ b/src/client/northstar/utils/Extensions.ts @@ -0,0 +1,20 @@ +interface String { + ReplaceAll(toReplace: string, replacement: string): string; +} + +String.prototype.ReplaceAll = function (toReplace: string, replacement: string): string { + var target = this; + return target.split(toReplace).join(replacement); +} + +interface Math { + log10(val: number): number; +} + +Math.log10 = function (val: number): number { + return Math.log(val) / Math.LN10; +} + +declare interface ObjectConstructor { + assign(...objects: Object[]): Object; +} diff --git a/src/client/northstar/utils/GeometryUtil.ts b/src/client/northstar/utils/GeometryUtil.ts new file mode 100644 index 000000000..d5f3ba631 --- /dev/null +++ b/src/client/northstar/utils/GeometryUtil.ts @@ -0,0 +1,129 @@ +import { MathUtil, PIXIRectangle, PIXIPoint } from "./MathUtil"; + + +export class GeometryUtil { + + public static ComputeBoundingBox(points: { x: number, y: number }[], scale = 1, padding: number = 0): PIXIRectangle { + let minX: number = Number.MAX_VALUE; + let minY: number = Number.MAX_VALUE; + let maxX: number = Number.MIN_VALUE; + let maxY: number = Number.MIN_VALUE; + for (var i = 0; i < points.length; i++) { + if (points[i].x < minX) + minX = points[i].x; + if (points[i].y < minY) + minY = points[i].y; + if (points[i].x > maxX) + maxX = points[i].x; + if (points[i].y > maxY) + maxY = points[i].y; + } + return new PIXIRectangle(minX * scale - padding, minY * scale - padding, (maxX - minX) * scale + padding * 2, (maxY - minY) * scale + padding * 2); + } + + public static RectangleOverlap(rect1: PIXIRectangle, rect2: PIXIRectangle) { + let x_overlap = Math.max(0, Math.min(rect1.right, rect2.right) - Math.max(rect1.left, rect2.left)); + let y_overlap = Math.max(0, Math.min(rect1.bottom, rect2.bottom) - Math.max(rect1.top, rect2.top)); + return x_overlap * y_overlap; + } + + public static RotatePoints(center: { x: number, y: number }, points: { x: number, y: number }[], angle: number): PIXIPoint[] { + const rotate = (cx: number, cy: number, x: number, y: number, angle: number) => { + const radians = angle, + cos = Math.cos(radians), + sin = Math.sin(radians), + nx = (cos * (x - cx)) + (sin * (y - cy)) + cx, + ny = (cos * (y - cy)) - (sin * (x - cx)) + cy; + return new PIXIPoint(nx, ny); + } + return points.map(p => rotate(center.x, center.y, p.x, p.y, angle)); + } + + public static LineByLeastSquares(points: { x: number, y: number }[]): PIXIPoint[] { + let sum_x: number = 0; + let sum_y: number = 0; + let sum_xy: number = 0; + let sum_xx: number = 0; + let count: number = 0; + + let x: number = 0; + let y: number = 0; + + + if (points.length === 0) { + return []; + } + + for (let v = 0; v < points.length; v++) { + x = points[v].x; + y = points[v].y; + sum_x += x; + sum_y += y; + sum_xx += x * x; + sum_xy += x * y; + count++; + } + + let m = (count * sum_xy - sum_x * sum_y) / (count * sum_xx - sum_x * sum_x); + let b = (sum_y / count) - (m * sum_x) / count; + let result: PIXIPoint[] = new Array(); + + for (let v = 0; v < points.length; v++) { + x = points[v].x; + y = x * m + b; + result.push(new PIXIPoint(x, y)); + } + return result; + } + + // public static PointInsidePolygon(vs:Point[], x:number, y:number):boolean { + // // ray-casting algorithm based on + // // http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html + + // var inside = false; + // for (var i = 0, j = vs.length - 1; i < vs.length; j = i++) { + // var xi = vs[i].x, yi = vs[i].y; + // var xj = vs[j].x, yj = vs[j].y; + + // var intersect = ((yi > y) != (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); + // if (intersect) + // inside = !inside; + // } + + // return inside; + // }; + + public static IntersectLines(x1: number, y1: number, x2: number, y2: number, x3: number, y3: number, x4: number, y4: number): boolean { + let a1: number, a2: number, b1: number, b2: number, c1: number, c2: number; + let r1: number, r2: number, r3: number, r4: number; + let denom: number, offset: number, num: number; + + a1 = y2 - y1; + b1 = x1 - x2; + c1 = (x2 * y1) - (x1 * y2); + r3 = ((a1 * x3) + (b1 * y3) + c1); + r4 = ((a1 * x4) + (b1 * y4) + c1); + + if ((r3 !== 0) && (r4 !== 0) && (MathUtil.Sign(r3) === MathUtil.Sign(r4))) { + return false; + } + + a2 = y4 - y3; + b2 = x3 - x4; + c2 = (x4 * y3) - (x3 * y4); + + r1 = (a2 * x1) + (b2 * y1) + c2; + r2 = (a2 * x2) + (b2 * y2) + c2; + + if ((r1 !== 0) && (r2 !== 0) && (MathUtil.Sign(r1) === MathUtil.Sign(r2))) { + return false; + } + + denom = (a1 * b2) - (a2 * b1); + + if (denom === 0) { + return false; + } + return true; + } +} \ No newline at end of file diff --git a/src/client/northstar/utils/IDisposable.ts b/src/client/northstar/utils/IDisposable.ts new file mode 100644 index 000000000..5e9843326 --- /dev/null +++ b/src/client/northstar/utils/IDisposable.ts @@ -0,0 +1,3 @@ +export interface IDisposable { + Dispose(): void; +} \ No newline at end of file diff --git a/src/client/northstar/utils/IEquatable.ts b/src/client/northstar/utils/IEquatable.ts new file mode 100644 index 000000000..2f81c2478 --- /dev/null +++ b/src/client/northstar/utils/IEquatable.ts @@ -0,0 +1,3 @@ +export interface IEquatable { + Equals(other: Object): boolean; +} \ No newline at end of file diff --git a/src/client/northstar/utils/KeyCodes.ts b/src/client/northstar/utils/KeyCodes.ts new file mode 100644 index 000000000..044569ffe --- /dev/null +++ b/src/client/northstar/utils/KeyCodes.ts @@ -0,0 +1,137 @@ +/** + * Class contains the keycodes for keys on your keyboard. + * + * Useful for auto completion: + * + * ``` + * switch (event.key) + * { + * case KeyCode.UP: + * { + * // Up key pressed + * break; + * } + * case KeyCode.DOWN: + * { + * // Down key pressed + * break; + * } + * case KeyCode.LEFT: + * { + * // Left key pressed + * break; + * } + * case KeyCode.RIGHT: + * { + * // Right key pressed + * break; + * } + * default: + * { + * // ignore + * break; + * } + * } + * ``` + */ +export class KeyCodes +{ + public static TAB:number = 9; + public static CAPS_LOCK:number = 20; + public static SHIFT:number = 16; + public static CONTROL:number = 17; + public static SPACE:number = 32; + public static DOWN:number = 40; + public static UP:number = 38; + public static LEFT:number = 37; + public static RIGHT:number = 39; + public static ESCAPE:number = 27; + public static F1:number = 112; + public static F2:number = 113; + public static F3:number = 114; + public static F4:number = 115; + public static F5:number = 116; + public static F6:number = 117; + public static F7:number = 118; + public static F8:number = 119; + public static F9:number = 120; + public static F10:number = 121; + public static F11:number = 122; + public static F12:number = 123; + public static INSERT:number = 45; + public static HOME:number = 36; + public static PAGE_UP:number = 33; + public static PAGE_DOWN:number = 34; + public static DELETE:number = 46; + public static END:number = 35; + public static ENTER:number = 13; + public static BACKSPACE:number = 8; + public static NUMPAD_0:number = 96; + public static NUMPAD_1:number = 97; + public static NUMPAD_2:number = 98; + public static NUMPAD_3:number = 99; + public static NUMPAD_4:number = 100; + public static NUMPAD_5:number = 101; + public static NUMPAD_6:number = 102; + public static NUMPAD_7:number = 103; + public static NUMPAD_8:number = 104; + public static NUMPAD_9:number = 105; + public static NUMPAD_DIVIDE:number = 111; + public static NUMPAD_ADD:number = 107; + public static NUMPAD_ENTER:number = 13; + public static NUMPAD_DECIMAL:number = 110; + public static NUMPAD_SUBTRACT:number = 109; + public static NUMPAD_MULTIPLY:number = 106; + public static SEMICOLON:number = 186; + public static EQUAL:number = 187; + public static COMMA:number = 188; + public static MINUS:number = 189; + public static PERIOD:number = 190; + public static SLASH:number = 191; + public static BACKQUOTE:number = 192; + public static LEFTBRACKET:number = 219; + public static BACKSLASH:number = 220; + public static RIGHTBRACKET:number = 221; + public static QUOTE:number = 222; + public static ALT:number = 18; + public static COMMAND:number = 15; + public static NUMPAD:number = 21; + public static A:number = 65; + public static B:number = 66; + public static C:number = 67; + public static D:number = 68; + public static E:number = 69; + public static F:number = 70; + public static G:number = 71; + public static H:number = 72; + public static I:number = 73; + public static J:number = 74; + public static K:number = 75; + public static L:number = 76; + public static M:number = 77; + public static N:number = 78; + public static O:number = 79; + public static P:number = 80; + public static Q:number = 81; + public static R:number = 82; + public static S:number = 83; + public static T:number = 84; + public static U:number = 85; + public static V:number = 86; + public static W:number = 87; + public static X:number = 88; + public static Y:number = 89; + public static Z:number = 90; + public static NUM_0:number = 48; + public static NUM_1:number = 49; + public static NUM_2:number = 50; + public static NUM_3:number = 51; + public static NUM_4:number = 52; + public static NUM_5:number = 53; + public static NUM_6:number = 54; + public static NUM_7:number = 55; + public static NUM_8:number = 56; + public static NUM_9:number = 57; + public static SUBSTRACT:number = 189; + public static ADD:number = 187; +} \ No newline at end of file diff --git a/src/client/northstar/utils/MathUtil.ts b/src/client/northstar/utils/MathUtil.ts new file mode 100644 index 000000000..3ed8628ee --- /dev/null +++ b/src/client/northstar/utils/MathUtil.ts @@ -0,0 +1,236 @@ + + +export class PIXIPoint { + public x: number; + public y: number; + constructor(x: number, y: number) { + this.x = x; + this.y = y; + } +} +export class PIXIRectangle { + public x: number; + public y: number; + public width: number; + public height: number + public get left() { return this.x } + public get right() { return this.x + this.width; } + public get top() { return this.y } + public get bottom() { return this.top + this.height } + constructor(x: number, y: number, width: number, height: number) { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + } +} + +export class MathUtil { + + public static EPSILON: number = 0.001; + + public static Sign(value: number): number { + return value >= 0 ? 1 : -1; + } + + public static AddPoint(p1: PIXIPoint, p2: PIXIPoint, inline: boolean = false): PIXIPoint { + if (inline) { + p1.x += p2.x; + p1.y += p2.y; + return p1; + } + else { + return new PIXIPoint(p1.x + p2.x, p1.y + p2.y); + } + } + + public static Perp(p1: PIXIPoint): PIXIPoint { + return new PIXIPoint(-p1.y, p1.x); + } + + public static DividePoint(p1: PIXIPoint, by: number, inline: boolean = false): PIXIPoint { + if (inline) { + p1.x /= by; + p1.y /= by; + return p1; + } + else { + return new PIXIPoint(p1.x / by, p1.y / by); + } + } + + public static MultiplyConstant(p1: PIXIPoint, by: number, inline: boolean = false) { + if (inline) { + p1.x *= by; + p1.y *= by; + return p1; + } + else { + return new PIXIPoint(p1.x * by, p1.y * by); + } + } + + public static SubtractPoint(p1: PIXIPoint, p2: PIXIPoint, inline: boolean = false): PIXIPoint { + if (inline) { + p1.x -= p2.x; + p1.y -= p2.y; + return p1; + } + else { + return new PIXIPoint(p1.x - p2.x, p1.y - p2.y); + } + } + + public static Area(rect: PIXIRectangle): number { + return rect.width * rect.height; + } + + public static DistToLineSegment(v: PIXIPoint, w: PIXIPoint, p: PIXIPoint) { + // Return minimum distance between line segment vw and point p + var l2 = MathUtil.DistSquared(v, w); // i.e. |w-v|^2 - avoid a sqrt + if (l2 == 0.0) return MathUtil.Dist(p, v); // v == w case + // Consider the line extending the segment, parameterized as v + t (w - v). + // We find projection of point p onto the line. + // It falls where t = [(p-v) . (w-v)] / |w-v|^2 + // We clamp t from [0,1] to handle points outside the segment vw. + var dot = MathUtil.Dot( + MathUtil.SubtractPoint(p, v), + MathUtil.SubtractPoint(w, v)) / l2; + var t = Math.max(0, Math.min(1, dot)); + // Projection falls on the segment + var projection = MathUtil.AddPoint(v, + MathUtil.MultiplyConstant( + MathUtil.SubtractPoint(w, v), t)); + return MathUtil.Dist(p, projection); + } + + public static LineSegmentIntersection(ps1: PIXIPoint, pe1: PIXIPoint, ps2: PIXIPoint, pe2: PIXIPoint): PIXIPoint | undefined { + var a1 = pe1.y - ps1.y; + var b1 = ps1.x - pe1.x; + + var a2 = pe2.y - ps2.y; + var b2 = ps2.x - pe2.x; + + var delta = a1 * b2 - a2 * b1; + if (delta == 0) { + return undefined; + } + var c2 = a2 * ps2.x + b2 * ps2.y; + var c1 = a1 * ps1.x + b1 * ps1.y; + var invdelta = 1 / delta; + return new PIXIPoint((b2 * c1 - b1 * c2) * invdelta, (a1 * c2 - a2 * c1) * invdelta); + } + + public static PointInPIXIRectangle(p: PIXIPoint, rect: PIXIRectangle): boolean { + if (p.x < rect.left - this.EPSILON) + return false; + if (p.x > rect.right + this.EPSILON) + return false; + if (p.y < rect.top - this.EPSILON) + return false; + if (p.y > rect.bottom + this.EPSILON) + return false; + + return true; + } + + public static LinePIXIRectangleIntersection(lineFrom: PIXIPoint, lineTo: PIXIPoint, rect: PIXIRectangle): Array { + var r1 = new PIXIPoint(rect.left, rect.top); + var r2 = new PIXIPoint(rect.right, rect.top); + var r3 = new PIXIPoint(rect.right, rect.bottom); + var r4 = new PIXIPoint(rect.left, rect.bottom); + var ret = new Array(); + var dist = this.Dist(lineFrom, lineTo) + var inter = this.LineSegmentIntersection(lineFrom, lineTo, r1, r2); + if (inter != null && this.PointInPIXIRectangle(inter, rect) && + this.Dist(inter, lineFrom) < dist && this.Dist(inter, lineTo) < dist) + ret.push(inter); + inter = this.LineSegmentIntersection(lineFrom, lineTo, r2, r3); + if (inter != null && this.PointInPIXIRectangle(inter, rect) && + this.Dist(inter, lineFrom) < dist && this.Dist(inter, lineTo) < dist) + ret.push(inter); + inter = this.LineSegmentIntersection(lineFrom, lineTo, r3, r4); + if (inter != null && this.PointInPIXIRectangle(inter, rect) && + this.Dist(inter, lineFrom) < dist && this.Dist(inter, lineTo) < dist) + ret.push(inter); + inter = this.LineSegmentIntersection(lineFrom, lineTo, r4, r1); + if (inter != null && this.PointInPIXIRectangle(inter, rect) && + this.Dist(inter, lineFrom) < dist && this.Dist(inter, lineTo) < dist) + ret.push(inter); + return ret; + } + + public static Intersection(rect1: PIXIRectangle, rect2: PIXIRectangle): PIXIRectangle { + const left = Math.max(rect1.x, rect2.x); + const right = Math.min(rect1.x + rect1.width, rect2.x + rect2.width); + const top = Math.max(rect1.y, rect2.y); + const bottom = Math.min(rect1.y + rect1.height, rect2.y + rect2.height); + return new PIXIRectangle(left, top, right - left, bottom - top); + } + + public static Dist(p1: PIXIPoint, p2: PIXIPoint): number { + return Math.sqrt(MathUtil.DistSquared(p1, p2)); + } + + public static Dot(p1: PIXIPoint, p2: PIXIPoint): number { + return p1.x * p2.x + p1.y * p2.y + } + + public static Normalize(p1: PIXIPoint) { + var d = this.Length(p1); + return new PIXIPoint(p1.x / d, p1.y / d); + } + + public static Length(p1: PIXIPoint): number { + return Math.sqrt(p1.x * p1.x + p1.y * p1.y); + } + + public static DistSquared(p1: PIXIPoint, p2: PIXIPoint): number { + const a = p1.x - p2.x; + const b = p1.y - p2.y; + return (a * a + b * b) + } + + public static RectIntersectsRect(r1: PIXIRectangle, r2: PIXIRectangle): boolean { + return !(r2.x > r1.x + r1.width || + r2.x + r2.width < r1.x || + r2.y > r1.y + r1.height || + r2.y + r2.height < r1.y); + } + + public static ArgMin(temp: number[]): number { + let index = 0; + let value = temp[0]; + for (let i = 1; i < temp.length; i++) { + if (temp[i] < value) { + value = temp[i]; + index = i; + } + } + return index; + } + + public static ArgMax(temp: number[]): number { + let index = 0; + let value = temp[0]; + for (let i = 1; i < temp.length; i++) { + if (temp[i] > value) { + value = temp[i]; + index = i; + } + } + return index; + } + + public static Combinations(chars: T[]) { + let result = new Array(); + let f = (prefix: any, chars: any) => { + for (let i = 0; i < chars.length; i++) { + result.push(prefix.concat(chars[i])); + f(prefix.concat(chars[i]), chars.slice(i + 1)); + } + }; + f([], chars); + return result; + } +} \ No newline at end of file diff --git a/src/client/northstar/utils/PartialClass.ts b/src/client/northstar/utils/PartialClass.ts new file mode 100644 index 000000000..2f20de96f --- /dev/null +++ b/src/client/northstar/utils/PartialClass.ts @@ -0,0 +1,7 @@ + +export class PartialClass { + + constructor(data?: Partial) { + Object.assign(this, data); + } +} \ No newline at end of file diff --git a/src/client/northstar/utils/Utils.ts b/src/client/northstar/utils/Utils.ts new file mode 100644 index 000000000..b35dce820 --- /dev/null +++ b/src/client/northstar/utils/Utils.ts @@ -0,0 +1,75 @@ +import { IBaseBrushable } from '../core/brusher/IBaseBrushable' +import { IBaseFilterConsumer } from '../core/filter/IBaseFilterConsumer' +import { IBaseFilterProvider } from '../core/filter/IBaseFilterProvider' +import { AggregateFunction } from '../model/idea/idea' + +export class Utils { + + public static EqualityHelper(a: Object, b: Object): boolean { + if (a === b) return true; + if (a === undefined && b !== undefined) return false; + if (a === null && b !== null) return false; + if (b === undefined && a !== undefined) return false; + if (b === null && a !== null) return false; + if ((a).constructor.name !== (b).constructor.name) return false; + return true; + } + + public static LowercaseFirstLetter(str: string) { + return str.charAt(0).toUpperCase() + str.slice(1); + } + + // + // this Type Guard tests if dropTarget is an IDropTarget. If it is, it coerces the compiler + // to treat the dropTarget parameter as an IDropTarget *ouside* this function scope (ie, in + // the scope of where this function is called from). + // + + public static isBaseBrushable(obj: Object): obj is IBaseBrushable { + let typed = >obj; + return typed != null && typed.BrusherModels !== undefined; + } + + public static isBaseFilterProvider(obj: Object): obj is IBaseFilterProvider { + let typed = obj; + return typed != null && typed.FilterModels !== undefined; + } + + public static isBaseFilterConsumer(obj: Object): obj is IBaseFilterConsumer { + let typed = obj; + return typed != null && typed.FilterOperand !== undefined; + } + + public static EncodeQueryData(data: any): string { + const ret = []; + for (let d in data) { + ret.push(encodeURIComponent(d) + "=" + encodeURIComponent(data[d])); + } + return ret.join("&"); + } + + public static ToVegaAggregationString(agg: AggregateFunction): string { + if (agg === AggregateFunction.Avg) { + return "average"; + } + else if (agg === AggregateFunction.Count) { + return "count"; + } + else { + return ""; + } + } + + public static GetQueryVariable(variable: string) { + let query = window.location.search.substring(1); + let vars = query.split("&"); + for (let i = 0; i < vars.length; i++) { + let pair = vars[i].split("="); + if (decodeURIComponent(pair[0]) == variable) { + return decodeURIComponent(pair[1]); + } + } + return undefined; + } +} + diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index ac51a7d87..b27f63e52 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -1,4 +1,4 @@ -import { action, configure, observable, runInAction, trace, computed } from 'mobx'; +import { action, configure, observable, runInAction, trace, computed, reaction } from 'mobx'; import "normalize.css"; import * as React from 'react'; import * as ReactDOM from 'react-dom'; @@ -22,7 +22,6 @@ import "./Main.scss"; import { observer } from 'mobx-react'; import { InkingControl } from './InkingControl'; import { RouteStore } from '../../server/RouteStore'; -import { json } from 'body-parser'; import { library } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faFont } from '@fortawesome/free-solid-svg-icons'; @@ -42,9 +41,10 @@ import { ServerUtils } from '../../server/ServerUtil'; import { CurrentUserUtils } from '../../server/authentication/models/current_user_utils'; import { Field, Opt } from '../../fields/Field'; import { ListField } from '../../fields/ListField'; -import { map } from 'bluebird'; import { Gateway, Settings } from '../northstar/manager/Gateway'; -import { Catalog } from '../northstar/model/idea/idea'; +import { Catalog, Schema, Attribute, AttributeGroup } from '../northstar/model/idea/idea'; +import { ArrayUtil } from '../northstar/utils/ArrayUtil'; +import '../northstar/model/ModelExtensions' @observer export class Main extends React.Component { @@ -88,16 +88,45 @@ export class Main extends React.Component { this.initEventListeners(); Documents.initProtos(() => this.initAuthenticationRouters()); + + reaction(() => [this.mainContainer, this.ActiveSchema], + () => { + if (this.mainContainer && this.ActiveSchema) { + if (!this.mainContainer!.GetTAsync(KeyStore.ActiveDB, ListField, field => this.NorthstarCatalog = field!.Data as Document[])) { + this.NorthstarCatalog = this.GetAllAttributes().map(a => Documents.HistogramDocument({ width: 200, height: 200, title: a.displayName! })); + this.mainContainer!.SetData(KeyStore.ActiveDB, this.NorthstarCatalog, ListField); + } + } + }) } + NorthstarCatalog: Document[] = []; + @observable ActiveSchema: Schema | undefined; @action SetNorthstarCatalog(ctlog: Catalog) { this._northstarCatalog = ctlog; - if (this._northstarCatalog) { + if (this._northstarCatalog && this._northstarCatalog.schemas) { console.log("CATALOG " + this._northstarCatalog.schemas); + this.ActiveSchema = ArrayUtil.FirstOrDefault(this._northstarCatalog.schemas!, (s: Schema) => s.displayName === "mimic"); } } + public GetAllAttributes() { + 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; + } async initializeNorthstar(): Promise { - let envPath = "assets/env.json"; + let envPath = "/assets/env.json"; const response = await fetch(envPath, { redirect: "follow", method: "GET", @@ -251,7 +280,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 addSchemaNode = action(() => Documents.SchemaDocument(this.NorthstarCatalog, { width: 200, height: 200, title: "a schema collection" })); 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" })); @@ -269,7 +298,9 @@ export class Main extends React.Component { [React.createRef(), "table", "Add Schema", addSchemaNode], ] - let addClick = (creator: () => Document) => action(() => this.mainfreeform!.GetList(KeyStore.Data, []).push(creator())); + let addClick = (creator: () => Document) => action(() => { + this.mainfreeform!.GetList(KeyStore.Data, []).push(creator()) + }); return < div id="add-nodes-menu" > diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index ce72ab64b..2f0459f88 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -19,6 +19,7 @@ import { KeyValueBox } from "./KeyValueBox"; import { PDFBox } from "./PDFBox"; import { VideoBox } from "./VideoBox"; import { WebBox } from "./WebBox"; +import { HistogramBox } from "./HistogramBox"; import React = require("react"); const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this? @@ -47,8 +48,7 @@ export class DocumentContentsView extends React.Component { console.log(test) }} diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index b6d50bffb..f6343c631 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -7,7 +7,6 @@ import { TextField } from "../../../fields/TextField"; import { NumberField } from "../../../fields/NumberField"; import { RichTextField } from "../../../fields/RichTextField"; import { ImageField } from "../../../fields/ImageField"; -import { WebField } from "../../../fields/WebField"; import { VideoField } from "../../../fields/VideoField" import { Key } from "../../../fields/Key"; import { FormattedTextBox } from "./FormattedTextBox"; @@ -64,9 +63,11 @@ export class FieldView extends React.Component { } else if (field instanceof AudioField) { return - } else if (field instanceof Document) { + } + else if (field instanceof Document) { return
{field.Title}
- } else if (field instanceof ListField) { + } + else if (field instanceof ListField) { return (
{(field as ListField).Data.map(f => { return f instanceof Document ? f.Title : f.GetValue().toString(); diff --git a/src/client/views/nodes/HistogramBox.scss b/src/client/views/nodes/HistogramBox.scss new file mode 100644 index 000000000..04bf1d732 --- /dev/null +++ b/src/client/views/nodes/HistogramBox.scss @@ -0,0 +1,8 @@ +.histogrambox-container { + padding: 0vw; + position: relative; + text-align: center; + 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 new file mode 100644 index 000000000..0fcc25e66 --- /dev/null +++ b/src/client/views/nodes/HistogramBox.tsx @@ -0,0 +1,67 @@ +import React = require("react") +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 { 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"; + +@observer +export class HistogramBox extends React.Component { + + public static LayoutString(fieldStr: string = "DataKey") { return FieldView.LayoutString(HistogramBox, fieldStr) } + + constructor(props: FieldViewProps) { + super(props); + } + + @observable _histoResult?: HistogramResult; + _histoOp?: HistogramOperation; + + componentDidMount() { + Main.Instance.GetAllAttributes().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; + } + } + } + } + return str; + } + + render() { + if (!this._histoResult) + return (null); + return ( +
+ `HISTOGRAM RESULT : ${this.twoString()}` +
+ ) + } +} \ No newline at end of file diff --git a/src/fields/KeyStore.ts b/src/fields/KeyStore.ts index 68883d6f1..319702cc4 100644 --- a/src/fields/KeyStore.ts +++ b/src/fields/KeyStore.ts @@ -28,6 +28,7 @@ export namespace KeyStore { export const SchemaSplitPercentage = new Key("SchemaSplitPercentage"); export const Caption = new Key("Caption"); export const ActiveFrame = new Key("ActiveFrame"); + export const ActiveDB = new Key("ActiveDB"); export const DocumentText = new Key("DocumentText"); export const LinkedToDocs = new Key("LinkedToDocs"); export const LinkedFromDocs = new Key("LinkedFromDocs"); -- 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') 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') 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') 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') 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') 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') 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') 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 ab78b1514ac16154d443d1d4a117a5fcaf891794 Mon Sep 17 00:00:00 2001 From: bob Date: Wed, 27 Mar 2019 16:12:36 -0400 Subject: converted histograms to % coords to avoid re-rendering. --- src/client/northstar/utils/SizeConverter.ts | 82 +++++------- src/client/views/nodes/HistogramBox.scss | 22 +++- src/client/views/nodes/HistogramBox.tsx | 146 +++++++++++++-------- src/client/views/nodes/HistogramBoxPrimitives.scss | 19 ++- src/client/views/nodes/HistogramBoxPrimitives.tsx | 106 +++++++++++---- 5 files changed, 237 insertions(+), 138 deletions(-) (limited to 'src/client/northstar') diff --git a/src/client/northstar/utils/SizeConverter.ts b/src/client/northstar/utils/SizeConverter.ts index 2dc2a7557..ffd162a83 100644 --- a/src/client/northstar/utils/SizeConverter.ts +++ b/src/client/northstar/utils/SizeConverter.ts @@ -1,68 +1,48 @@ 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"; +import { observable, action, computed } from "mobx"; 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; - + 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 RenderDimension: number = 300; + + @observable _leftOffset: number = 40; + @observable _rightOffset: number = 20; + @observable _topOffset: number = 20; + @observable _bottomOffset: number = 45; + @observable _labelAngle: number = 0; + @observable _isSmall: boolean = false; + @observable public Initialized = 0; + + @action public SetIsSmall(isSmall: boolean) { this._isSmall = isSmall; } + @action public SetLabelAngle(angle: number) { this._labelAngle = angle; } + @computed public get IsSmall() { return this._isSmall; } + @computed public get LabelAngle() { return this._labelAngle; } + @computed public get LeftOffset() { return this.IsSmall ? 5 : this._leftOffset; } + @computed public get RightOffset() { return this.IsSmall ? 5 : !this._labelAngle ? this._bottomOffset : Math.max(this._rightOffset, Math.cos(this._labelAngle) * (this.MaxLabelSizes[0].x + 18)); } + @computed public get TopOffset() { return this.IsSmall ? 5 : this._topOffset; } + @computed public get BottomOffset() { return this.IsSmall ? 25 : !this._labelAngle ? this._bottomOffset : Math.max(this._bottomOffset, Math.sin(this._labelAngle) * (this.MaxLabelSizes[0].x + 18)) + 18; } + + public SetVisualBinRanges(visualBinRanges: Array) { + this.Initialized++; 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, + var metricsX = { width: 75 }; // 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._leftOffset = Math.max(10, metricsY.width + 10 + 20); 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); @@ -94,11 +74,11 @@ export class SizeConverter { } public DataToScreenX(x: number): number { - return (((x - this.DataMins[0]) / this.DataRanges[0]) * (this.RenderSize[0]) + (this.LeftOffset)); + return ((x - this.DataMins[0]) / this.DataRanges[0]) * this.RenderDimension; } 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); + var retY = ((y - this.DataMins[1]) / this.DataRanges[1]) * this.RenderDimension; + return flip ? (this.RenderDimension) - retY : retY; } public DataToScreenCoord(v: number, axis: number) { if (axis == 0) diff --git a/src/client/views/nodes/HistogramBox.scss b/src/client/views/nodes/HistogramBox.scss index 00ad099ac..7c28fc99e 100644 --- a/src/client/views/nodes/HistogramBox.scss +++ b/src/client/views/nodes/HistogramBox.scss @@ -5,14 +5,28 @@ width: 100%; height: 100%; } - .histogrambox-gridlabel { - position:absolute; - transform-origin: left top; - } .histogrambox-xaxislabel { position:absolute; width:100%; text-align: center; bottom:0; + font-size: 12; + } + + .histogrambox-container { + position:absolute; + width:100%; + height: 100%; + } + .histogramLabelPrimitives-gridlabel { + position:absolute; + transform-origin: left top; + font-size: 12; + } + .histogramLabelPrimitives-placer { + position:absolute; + width:100%; + height:100%; + pointer-events: none; } \ No newline at end of file diff --git a/src/client/views/nodes/HistogramBox.tsx b/src/client/views/nodes/HistogramBox.tsx index c9537bcf8..2291d1418 100644 --- a/src/client/views/nodes/HistogramBox.tsx +++ b/src/client/views/nodes/HistogramBox.tsx @@ -1,5 +1,5 @@ import React = require("react") -import { computed, observable, reaction, runInAction } from "mobx"; +import { computed, observable, reaction, runInAction, trace, action } from "mobx"; import { observer } from "mobx-react"; import Measure from "react-measure"; import { Dictionary } from "typescript-collections"; @@ -21,22 +21,20 @@ import { StyleConstants } from "../../northstar/utils/StyleContants"; import "./../../northstar/utils/Extensions"; import { FieldView, FieldViewProps } from './FieldView'; import "./HistogramBox.scss"; -import { HistogramBoxPrimitives } from './HistogramBoxPrimitives'; +import { HistogramBoxPrimitives, HistogramBoxPrimitivesProps } from './HistogramBoxPrimitives'; @observer export class HistogramBox extends React.Component { public static LayoutString(fieldStr: string = "DataKey") { return FieldView.LayoutString(HistogramBox, fieldStr) } + public HitTargets: Dictionary = new Dictionary(); - @observable private _panelWidth: number = 100; - @observable private _panelHeight: number = 100; + @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; - public HitTargets: Dictionary = new Dictionary(); + @observable public SizeConverter: SizeConverter = new SizeConverter(); - @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; } @@ -48,93 +46,127 @@ export class HistogramBox extends React.Component { 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._panelHeight, this._panelWidth], - () => this.SizeConverter = new SizeConverter({ x: this._panelWidth, y: this._panelHeight }, this.VisualBinRanges, Math.PI / 4)); - 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))); + (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]); - } - }); + 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.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 }) => +
+
+ + +
+
{label}
+
+ } +
+ ) + } +} + +@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 }); + } - drawLine(xFrom: number, yFrom: number, width: number, height: number) { - return
; + @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.SizeConverter!; - if (!sc || !this.VisualBinRanges.length) + let sc = this.props.HistoBox.SizeConverter; + let vb = this.props.HistoBox.VisualBinRanges; + if (!vb.length || !sc.Initialized) return (null); - let dim = sc.RenderSize[axis] / ((axis == 0 && this.VisualBinRanges[axis] instanceof NominalVisualBinRange) ? + 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 prims: JSX.Element[] = []; - let labels = this.VisualBinRanges[axis].GetLabels(); + let labels = vb[axis].GetLabels(); labels.map((binLabel, i) => { let r = sc.DataToScreenRange(binLabel.minValue!, binLabel.maxValue!, axis); - - 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 ? 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) { 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); - let rotation = 0; - if (axis == 0 && this.VisualBinRanges[axis] instanceof NominalVisualBinRange) { - 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; + 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( -
- {label} -
) +
+
+ {label} +
+
+ ) } }); return prims; } render() { - let label = this.HistoOp && this.HistoOp.X ? this.HistoOp.X.AttributeModel.DisplayName : "<...>"; let xaxislines = this.xaxislines; let yaxislines = this.yaxislines; - 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); - return ( - runInAction(() => { this._panelWidth = r.entry.width; this._panelHeight = r.entry.height })}> - {({ measureRef }) => -
- {xaxislines} - {yaxislines} - -
{label}
-
- } -
- ) + return
+ {xaxislines} + {yaxislines} +
} + } \ No newline at end of file diff --git a/src/client/views/nodes/HistogramBoxPrimitives.scss b/src/client/views/nodes/HistogramBoxPrimitives.scss index c88d3a227..85f2c092d 100644 --- a/src/client/views/nodes/HistogramBoxPrimitives.scss +++ b/src/client/views/nodes/HistogramBoxPrimitives.scss @@ -1,10 +1,25 @@ .histogramboxprimitives-border { - border: 1px; + border: 3px; border-style: solid; + border-color: #282828; pointer-events: none; position: absolute; - border-color: #282828; } .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 index 10f6515cf..06b318750 100644 --- a/src/client/views/nodes/HistogramBoxPrimitives.tsx +++ b/src/client/views/nodes/HistogramBoxPrimitives.tsx @@ -1,5 +1,5 @@ import React = require("react") -import { computed, observable, runInAction } from "mobx"; +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"; @@ -11,10 +11,9 @@ import { LABColor } from '../../northstar/utils/LABcolor'; import { PIXIRectangle } from "../../northstar/utils/MathUtil"; import { StyleConstants } from "../../northstar/utils/StyleContants"; import { HistogramBox } from "./HistogramBox"; -import "./HistogramBox.scss"; +import "./HistogramBoxPrimitives.scss"; import { HistogramOperation } from "../../northstar/operations/HistogramOperation"; import { FilterModel } from "../../northstar/core/filter/FilterModel"; -import { jSXElement } from "babel-types"; export interface HistogramBoxPrimitivesProps { HistoBox: HistogramBox; @@ -24,9 +23,10 @@ export interface HistogramBoxPrimitivesProps { export class HistogramBoxPrimitives extends React.Component { @observable _selectedPrims: HistogramBinPrimitive[] = []; - @computed - get selectedPrimitives() { - return this._selectedPrims.map((bp) => this.drawRect(bp.Rect, undefined, () => { }, "border")); + @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")); } private getSelectionToggle(histoOp: HistogramOperation, binPrimitives: HistogramBinPrimitive[], allBrushIndex: number, filterModel: FilterModel) { let allBrushPrim = ArrayUtil.FirstOrDefault(binPrimitives, bp => bp.BrushIndex == allBrushIndex); @@ -45,7 +45,7 @@ export class HistogramBoxPrimitives extends React.Component { @@ -56,23 +56,79 @@ export class HistogramBoxPrimitives extends React.Component 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, pair.c, toggle, "bar")))); + 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, toggle, "bar")))); return prims; }, [] as JSX.Element[]); } - drawRect(r: PIXIRectangle, color: number | undefined, tapHandler: () => void, classExt: string) { - return
{ if (e.button == 0) tapHandler() }} - style={{ - transform: `translate(${r.x}px,${r.y}px)`, - width: `${r.width - 1}`, - height: `${r.height}`, - background: color ? `${LABColor.RGBtoHexString(color)}` : "" - }} - /> + + private renderGridLinesAndLabels(axis: number) { + let sc = this.props.HistoBox.SizeConverter; + let vb = this.props.HistoBox.VisualBinRanges; + if (!vb.length || !sc.Initialized) + return (null); + + let prims: JSX.Element[] = []; + let labels = vb[axis].GetLabels(); + labels.map((binLabel, i) => { + let r = sc.DataToScreenRange(binLabel.minValue!, binLabel.maxValue!, axis); + + 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 ? r.xTo : r.xFrom, axis == 0 ? r.yFrom : r.yTo, axis == 0 ? 1 : r.xTo - r.xFrom, axis == 0 ? r.yTo - r.yFrom : 1)); + }); + return prims; + } + + drawLine(xFrom: number, yFrom: number, width: number, height: number) { + if (height < 0) { + yFrom += height; + height = -height; + } + if (width < 0) { + xFrom += width; + width = -width; + } + let transXpercent = (xFrom) / this.props.HistoBox.SizeConverter.RenderDimension; + let transYpercent = (yFrom) / this.props.HistoBox.SizeConverter.RenderDimension; + let trans2Xpercent = width == 1 ? "1px" : `${(xFrom + width) / this.props.HistoBox.SizeConverter.RenderDimension * 100}%`; + let trans2Ypercent = height == 1 ? "1px" : `${(yFrom + height) / this.props.HistoBox.SizeConverter.RenderDimension * 100}%`; + return
+
; + } + + drawRect(r: PIXIRectangle, barAxis: number, color: number | undefined, tapHandler: () => void, classExt: string) { + let widthPercent = (r.width - 0) / this.props.HistoBox.SizeConverter.RenderDimension; + let heightPercent = r.height / this.props.HistoBox.SizeConverter.RenderDimension; + let transXpercent = (r.x) / this.props.HistoBox.SizeConverter.RenderDimension; + let transYpercent = (r.y) / this.props.HistoBox.SizeConverter.RenderDimension; + return (
+
{ if (e.button == 0) tapHandler() }} + style={{ + borderBottomStyle: barAxis == 1 ? "none" : "solid", + borderLeftStyle: barAxis == 0 ? "none" : "solid", + width: `${widthPercent * 100}%`, + height: `${heightPercent * 100}%`, + background: color ? `${LABColor.RGBtoHexString(color)}` : "" + }} + />
); } render() { - return
+ if (!this.props.HistoBox.SizeConverter.Initialized) + return (null); + let xaxislines = this.xaxislines; + let yaxislines = this.yaxislines; + return
+ {xaxislines} + {yaxislines} {this.binPrimitives} {this.selectedPrimitives}
@@ -90,6 +146,7 @@ class HistogramBinPrimitive { public Color: number = StyleConstants.WARNING_COLOR; public Opacity: number = 1; public BrushIndex: number = 0; + public BarAxis: number = -1; } export class HistogramBinPrimitiveCollection { @@ -202,7 +259,7 @@ export class HistogramBinPrimitiveCollection { (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); + this.createBinPrimitive(-1, brush, PIXIRectangle.EMPTY, 0, xFrom, xTo, yFrom, yTo, dataColor, 1, unNormalizedValue); return returnBrushFactorSum; } @@ -213,7 +270,7 @@ export class HistogramBinPrimitiveCollection { 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(bin, brush, PIXIRectangle.EMPTY, 0, xFrom, xTo, yFrom, yTo, this.baseColorFromBrush(brush), 1, unNormalizedValue); + this.createBinPrimitive(-1, brush, PIXIRectangle.EMPTY, 0, xFrom, xTo, yFrom, yTo, this.baseColorFromBrush(brush), 1, unNormalizedValue); } return 0; } @@ -229,7 +286,7 @@ export class HistogramBinPrimitiveCollection { 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.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; @@ -247,7 +304,7 @@ export class HistogramBinPrimitiveCollection { this.sizeConverter.DataToScreenX(xValue + xMarginAbsolute) - this.sizeConverter.DataToScreenX(xValue - xMarginAbsolute), 2.0); - this.createBinPrimitive(bin, brush, marginRect, 0, xFrom, xTo, yFrom, yTo, + 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; @@ -262,7 +319,7 @@ export class HistogramBinPrimitiveCollection { return !marginResult ? 0 : marginResult.absolutMargin!; } - private createBinPrimitive(bin: Bin, brush: Brush, marginRect: PIXIRectangle, + 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( { @@ -272,7 +329,8 @@ export class HistogramBinPrimitiveCollection { BrushIndex: brush.brushIndex, Color: color, Opacity: opacity, - DataValue: dataValue + DataValue: dataValue, + BarAxis: barAxis }); this.BinPrimitives.push(binPrimitive); } -- 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') 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( +
+
+ {label} +
+
+ ) + } + 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 }) => -
-
- - -
-
{label}
-
- } -
- ) - } -} - 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( -
-
- {label} -
-
- ) - } - 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 da7a12f9b49b43534658524b1da846948fbf3947 Mon Sep 17 00:00:00 2001 From: bob Date: Fri, 29 Mar 2019 14:37:26 -0400 Subject: fixed some bugs added some small features to histograms. --- src/client/Server.ts | 4 ++-- src/client/documents/Documents.ts | 4 ++-- src/client/northstar/dash-nodes/HistogramBox.tsx | 17 ++++++++++++----- .../northstar/dash-nodes/HistogramBoxPrimitives.tsx | 5 ++++- src/client/northstar/utils/SizeConverter.ts | 2 +- src/client/util/DragManager.ts | 2 ++ src/client/views/Main.tsx | 6 +++--- .../collectionFreeForm/CollectionFreeFormView.scss | 20 ++++++++++---------- 8 files changed, 36 insertions(+), 24 deletions(-) (limited to 'src/client/northstar') diff --git a/src/client/Server.ts b/src/client/Server.ts index feafe9eb4..37e3c2c0d 100644 --- a/src/client/Server.ts +++ b/src/client/Server.ts @@ -75,7 +75,7 @@ export class Server { existingFields[id] = field; } } - SocketStub.SEND_FIELDS_REQUEST(neededFieldIds, (fields) => { + SocketStub.SEND_FIELDS_REQUEST(neededFieldIds, action((fields: FieldMap) => { for (let id of neededFieldIds) { let field = fields[id]; if (field) { @@ -104,7 +104,7 @@ export class Server { cb({ ...fields, ...existingFields }) } }, { fireImmediately: true }) - }); + })); }; if (callback) { fn(callback); diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 663ccae61..0bf275df8 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -190,8 +190,8 @@ export namespace Documents { return assignToDelegate(SetInstanceOptions(GetAudioPrototype(), options, [new URL(url), AudioField]), options); } - export function HistogramDocument(histoOp: HistogramOperation, options: DocumentOptions = {}, id?: string) { - return assignToDelegate(SetInstanceOptions(GetHistogramPrototype(), options, [histoOp, HistogramField], id).MakeDelegate(), options); + export function HistogramDocument(histoOp: HistogramOperation, options: DocumentOptions = {}, id?: string, delegId?: string) { + return assignToDelegate(SetInstanceOptions(GetHistogramPrototype(), options, [histoOp, HistogramField], id).MakeDelegate(delegId), options); } export function TextDocument(options: DocumentOptions = {}) { return assignToDelegate(SetInstanceOptions(GetTextPrototype(), options, ["", TextField]).MakeDelegate(), options); diff --git a/src/client/northstar/dash-nodes/HistogramBox.tsx b/src/client/northstar/dash-nodes/HistogramBox.tsx index 9f8c2cfd0..dba4ce900 100644 --- a/src/client/northstar/dash-nodes/HistogramBox.tsx +++ b/src/client/northstar/dash-nodes/HistogramBox.tsx @@ -9,7 +9,7 @@ import { CurrentUserUtils } from "../../../server/authentication/models/current_ 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 { AggregateBinRange, BinRange, DoubleValueAggregateResult, HistogramResult, Catalog, AggregateFunction } from "../../northstar/model/idea/idea"; import { ModelHelpers } from "../../northstar/model/ModelHelpers"; import { HistogramOperation } from "../../northstar/operations/HistogramOperation"; import { PIXIRectangle } from "../../northstar/utils/MathUtil"; @@ -21,6 +21,7 @@ import "../utils/Extensions" import "./HistogramBox.scss"; import { HistogramBoxPrimitives } from './HistogramBoxPrimitives'; import { HistogramLabelPrimitives } from "./HistogramLabelPrimitives"; +import { AttributeTransformationModel } from "../core/attribute/AttributeTransformationModel"; export interface HistogramPrimitivesProps { HistoBox: HistogramBox; @@ -104,7 +105,11 @@ 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() { @@ -138,12 +143,12 @@ export class HistogramBox extends React.Component { runInAction(() => { this.PanelWidth = r.entry.width; this.PanelHeight = r.entry.height })}> {({ measureRef }) =>
-
+
{labelY}
-
{
-
{labelX}
+
+ {labelX} +
} diff --git a/src/client/northstar/dash-nodes/HistogramBoxPrimitives.tsx b/src/client/northstar/dash-nodes/HistogramBoxPrimitives.tsx index d2f1be4fd..5e403eb9c 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 } from "mobx"; +import { computed, observable, runInAction, reaction } from "mobx"; import { observer } from "mobx-react"; import { Utils as DashUtils } from '../../../Utils'; import { AttributeTransformationModel } from "../../northstar/core/attribute/AttributeTransformationModel"; @@ -19,6 +19,9 @@ import "./HistogramBoxPrimitives.scss"; 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.HistogramResult, () => this._selectedPrims.length = 0); + } @observable _selectedPrims: HistogramBinPrimitive[] = []; @computed get xaxislines() { return this.renderGridLinesAndLabels(0); } @computed get yaxislines() { return this.renderGridLinesAndLabels(1); } diff --git a/src/client/northstar/utils/SizeConverter.ts b/src/client/northstar/utils/SizeConverter.ts index 30627dfd5..bb91ed4a7 100644 --- a/src/client/northstar/utils/SizeConverter.ts +++ b/src/client/northstar/utils/SizeConverter.ts @@ -62,7 +62,7 @@ export class SizeConverter { public DataToScreenPointRange(axis: number, bin: Bin, aggregateKey: AggregateKey) { var value = ModelHelpers.GetAggregateResult(bin, aggregateKey) as DoubleValueAggregateResult; - if (value.hasResult) + if (value && value.hasResult) return [this.DataToScreenCoord(value.result!, axis) - 5, this.DataToScreenCoord(value.result!, axis) + 5]; return [undefined, undefined]; diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 661fa4dc8..70b1c9829 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -186,6 +186,8 @@ export namespace DragManager { e.preventDefault(); x += e.movementX; y += e.movementY; + if (dragData instanceof DocumentDragData) + dragData.aliasOnDrop = e.ctrlKey || e.altKey; if (e.shiftKey) { abortDrag(); CollectionDockingView.Instance.StartOtherDrag(doc, { pageX: e.pageX, pageY: e.pageY, preventDefault: () => { }, button: 0 }); diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index 2f20b102c..75855c3d1 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -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._northstarSchemas, { width: 100, height: 400, title: "northstar schemas" })); + let addTreeNode = action(() => Documents.TreeDocument(this._northstarSchemas, { width: 250, 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" })); @@ -340,7 +340,7 @@ export class Main extends React.Component { 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) => { + Server.GetField(attr.displayName! + ".alias", action((field: Opt) => { if (field instanceof Document) { schemaDocuments.push(field); } else { @@ -349,7 +349,7 @@ export class Main extends React.Component { 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!)); + schemaDocuments.push(Documents.HistogramDocument(histoOp, { width: 200, height: 200, title: attr.displayName! }, undefined, attr.displayName! + ".alias")); } })); }); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss index 9c5e98005..215a75243 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss @@ -1,5 +1,15 @@ @import "../../global_variables"; +.collectionfreeformview { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + .inking-canvas { + transform-origin: 50000px 50000px; + } +} .collectionfreeformview-container { .collectionfreeformview > .jsx-parser { position: absolute; @@ -27,16 +37,6 @@ left: 0; width: 100%; height: 100%; - .collectionfreeformview { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - .inking-canvas { - transform-origin: 50000px 50000px; - } - } } .collectionfreeformview-overlay { .collectionfreeformview > .jsx-parser { -- 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') 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 6e0439f36216af6ee25ff9a65d296e6f9ff28fd3 Mon Sep 17 00:00:00 2001 From: bob Date: Fri, 29 Mar 2019 16:24:44 -0400 Subject: from last --- src/client/northstar/dash-nodes/HistogramBoxPrimitives.tsx | 3 --- 1 file changed, 3 deletions(-) (limited to 'src/client/northstar') diff --git a/src/client/northstar/dash-nodes/HistogramBoxPrimitives.tsx b/src/client/northstar/dash-nodes/HistogramBoxPrimitives.tsx index b8020c28c..648070241 100644 --- a/src/client/northstar/dash-nodes/HistogramBoxPrimitives.tsx +++ b/src/client/northstar/dash-nodes/HistogramBoxPrimitives.tsx @@ -269,9 +269,6 @@ 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); -- 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') 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') 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') 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') 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 From 0ae1eac2e2b26c0eee747c81ea1478118b4ec874 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Fri, 29 Mar 2019 23:58:43 -0400 Subject: from last --- src/client/northstar/dash-fields/HistogramField.ts | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'src/client/northstar') diff --git a/src/client/northstar/dash-fields/HistogramField.ts b/src/client/northstar/dash-fields/HistogramField.ts index 4a557e123..90be70b80 100644 --- a/src/client/northstar/dash-fields/HistogramField.ts +++ b/src/client/northstar/dash-fields/HistogramField.ts @@ -1,13 +1,11 @@ -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 { AttributeTransformationModel } from "../../../client/northstar/core/attribute/AttributeTransformationModel"; +import { HistogramOperation } from "../../../client/northstar/operations/HistogramOperation"; +import { BasicField } from "../../../fields/BasicField"; +import { Field, FieldId } from "../../../fields/Field"; import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils"; -import { ArrayUtil } from "../utils/ArrayUtil"; -import { Schema } from "../model/idea/idea"; +import { Types } from "../../../server/Message"; export class HistogramField extends BasicField { @@ -25,7 +23,7 @@ export class HistogramField extends BasicField { return dup; } toString(): string { - return JSON.stringify(this.omitKeys(this.Data, ['Links', 'BrushLinks', 'Result', 'BrushColors'])); + return JSON.stringify(this.omitKeys(this.Data, ['Links', 'BrushLinks', 'Result', 'BrushColors', 'FilterModels', 'FilterOperand'])); } Copy(): Field { -- cgit v1.2.3-70-g09d2 From 8448679e0a260ec881c54a10578bc464cd38f04e Mon Sep 17 00:00:00 2001 From: bob Date: Mon, 1 Apr 2019 17:05:42 -0400 Subject: added dragging multiple items. --- src/client/northstar/dash-nodes/HistogramBox.tsx | 4 +- src/client/util/DragManager.ts | 168 +++++++++++---------- src/client/views/DocumentDecorations.scss | 6 + src/client/views/DocumentDecorations.tsx | 109 +++++++++---- src/client/views/Main.tsx | 7 +- .../views/collections/CollectionDockingView.tsx | 11 +- src/client/views/collections/CollectionView.tsx | 2 +- .../views/collections/CollectionViewBase.tsx | 4 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 21 ++- src/client/views/nodes/DocumentView.tsx | 15 +- 10 files changed, 213 insertions(+), 134 deletions(-) (limited to 'src/client/northstar') diff --git a/src/client/northstar/dash-nodes/HistogramBox.tsx b/src/client/northstar/dash-nodes/HistogramBox.tsx index a968def96..49ebe5ebc 100644 --- a/src/client/northstar/dash-nodes/HistogramBox.tsx +++ b/src/client/northstar/dash-nodes/HistogramBox.tsx @@ -54,7 +54,7 @@ export class HistogramBox extends React.Component { @action dropX = (e: Event, de: DragManager.DropEvent) => { if (de.data instanceof DragManager.DocumentDragData) { - let h = de.data.draggedDocument.GetT(KeyStore.Data, HistogramField); + let h = de.data.draggedDocuments[0].GetT(KeyStore.Data, HistogramField); if (h && h != FieldWaiting) { this.HistoOp.X = h.Data.X; } @@ -65,7 +65,7 @@ export class HistogramBox extends React.Component { @action dropY = (e: Event, de: DragManager.DropEvent) => { if (de.data instanceof DragManager.DocumentDragData) { - let h = de.data.draggedDocument.GetT(KeyStore.Data, HistogramField); + let h = de.data.draggedDocuments[0].GetT(KeyStore.Data, HistogramField); if (h && h != FieldWaiting) { this.HistoOp.Y = h.Data.X; } diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 70b1c9829..9ffe964ef 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -14,9 +14,9 @@ export function setupDrag(_reference: React.RefObject, docFunc: document.removeEventListener("pointermove", onRowMove); document.removeEventListener('pointerup', onRowUp); - var dragData = new DragManager.DocumentDragData(docFunc()); + var dragData = new DragManager.DocumentDragData([docFunc()]); dragData.removeDocument = removeFunc; - DragManager.StartDocumentDrag(_reference.current!, dragData); + DragManager.StartDocumentDrag([_reference.current!], dragData); }); let onRowUp = action((e: PointerEvent): void => { document.removeEventListener("pointermove", onRowMove); @@ -27,7 +27,7 @@ export function setupDrag(_reference: React.RefObject, docFunc: if (e.button == 0) { e.stopPropagation(); if (e.shiftKey) { - CollectionDockingView.Instance.StartOtherDrag(docFunc(), e); + CollectionDockingView.Instance.StartOtherDrag([docFunc()], e); } else { document.addEventListener("pointermove", onRowMove); document.addEventListener('pointerup', onRowUp); @@ -101,20 +101,21 @@ export namespace DragManager { } export class DocumentDragData { - constructor(dragDoc: Document) { - this.draggedDocument = dragDoc; - this.droppedDocument = dragDoc; + constructor(dragDoc: Document[]) { + this.draggedDocuments = dragDoc; + this.droppedDocuments = dragDoc; } - draggedDocument: Document; - droppedDocument: Document; + draggedDocuments: Document[]; + droppedDocuments: Document[]; xOffset?: number; yOffset?: number; aliasOnDrop?: boolean; removeDocument?: (collectionDrop: CollectionView) => void; [id: string]: any; } - export function StartDocumentDrag(ele: HTMLElement, dragData: DocumentDragData, options?: DragOptions) { - StartDrag(ele, dragData, options, (dropData: { [id: string]: any }) => dropData.droppedDocument = dragData.aliasOnDrop ? dragData.draggedDocument.CreateAlias() : dragData.draggedDocument); + + export function StartDocumentDrag(eles: HTMLElement[], dragData: DocumentDragData, options?: DragOptions) { + StartDrag(eles, dragData, options, (dropData: { [id: string]: any }) => dropData.droppedDocuments = dragData.aliasOnDrop ? dragData.draggedDocuments.map(d => d.CreateAlias()) : dragData.draggedDocuments); } export class LinkDragData { @@ -125,49 +126,58 @@ export namespace DragManager { [id: string]: any; } export function StartLinkDrag(ele: HTMLElement, dragData: LinkDragData, options?: DragOptions) { - StartDrag(ele, dragData, options); + StartDrag([ele], dragData, options); } - function StartDrag(ele: HTMLElement, dragData: { [id: string]: any }, options?: DragOptions, finishDrag?: (dropData: { [id: string]: any }) => void) { + function StartDrag(eles: HTMLElement[], dragData: { [id: string]: any }, options?: DragOptions, finishDrag?: (dropData: { [id: string]: any }) => void) { if (!dragDiv) { dragDiv = document.createElement("div"); dragDiv.className = "dragManager-dragDiv" DragManager.Root().appendChild(dragDiv); } - const w = ele.offsetWidth, h = ele.offsetHeight; - const rect = ele.getBoundingClientRect(); - const scaleX = rect.width / w, scaleY = rect.height / h; - let x = rect.left, y = rect.top; - // const offsetX = e.x - rect.left, offsetY = e.y - rect.top; - - let dragElement = ele.cloneNode(true) as HTMLElement; - dragElement.style.opacity = "0.7"; - dragElement.style.position = "absolute"; - dragElement.style.bottom = ""; - dragElement.style.left = ""; - dragElement.style.transformOrigin = "0 0"; - dragElement.style.zIndex = "1000"; - dragElement.style.transform = `translate(${x}px, ${y}px) scale(${scaleX}, ${scaleY})`; - dragElement.style.width = `${rect.width / scaleX}px`; - dragElement.style.height = `${rect.height / scaleY}px`; - - // bcz: PDFs don't show up if you clone them because they contain a canvas. - // however, PDF's have a thumbnail field that contains an image of their canvas. - // So we replace the pdf's canvas with the image thumbnail - const doc: Document = dragData["draggedDocument"]; - if (doc) { - var pdfBox = dragElement.getElementsByClassName("pdfBox-cont")[0] as HTMLElement; - let thumbnail = doc.GetT(KeyStore.Thumbnail, ImageField); - if (pdfBox && pdfBox.childElementCount && thumbnail) { - let img = new Image(); - img!.src = thumbnail.toString(); - img!.style.position = "absolute"; - img!.style.width = `${rect.width / scaleX}px`; - img!.style.height = `${rect.height / scaleY}px`; - pdfBox.replaceChild(img!, pdfBox.children[0]) + + let scaleXs: number[] = []; + let scaleYs: number[] = []; + let xs: number[] = []; + let ys: number[] = []; + + const docs: Document[] = dragData instanceof DocumentDragData ? dragData.draggedDocuments : []; + let dragElements = eles.map(ele => { + const w = ele.offsetWidth, h = ele.offsetHeight; + const rect = ele.getBoundingClientRect(); + const scaleX = rect.width / w, scaleY = rect.height / h; + let x = rect.left, y = rect.top; + xs.push(x); ys.push(y); + scaleXs.push(scaleX); scaleYs.push(scaleY); + let dragElement = ele.cloneNode(true) as HTMLElement; + dragElement.style.opacity = "0.7"; + dragElement.style.position = "absolute"; + dragElement.style.bottom = ""; + dragElement.style.left = ""; + dragElement.style.transformOrigin = "0 0"; + dragElement.style.zIndex = "1000"; + dragElement.style.transform = `translate(${x}px, ${y}px) scale(${scaleX}, ${scaleY})`; + dragElement.style.width = `${rect.width / scaleX}px`; + dragElement.style.height = `${rect.height / scaleY}px`; + + // bcz: PDFs don't show up if you clone them because they contain a canvas. + // however, PDF's have a thumbnail field that contains an image of their canvas. + // So we replace the pdf's canvas with the image thumbnail + if (docs.length) { + var pdfBox = dragElement.getElementsByClassName("pdfBox-cont")[0] as HTMLElement; + let thumbnail = docs[0].GetT(KeyStore.Thumbnail, ImageField); + if (pdfBox && pdfBox.childElementCount && thumbnail) { + let img = new Image(); + img!.src = thumbnail.toString(); + img!.style.position = "absolute"; + img!.style.width = `${rect.width / scaleX}px`; + img!.style.height = `${rect.height / scaleY}px`; + pdfBox.replaceChild(img!, pdfBox.children[0]) + } } - } - dragDiv.appendChild(dragElement); + dragDiv.appendChild(dragElement); + return dragElement; + }); let hideSource = false; if (options) { @@ -177,62 +187,64 @@ export namespace DragManager { hideSource = options.hideSource(); } } - const wasHidden = ele.hidden; - if (hideSource) { - ele.hidden = true; - } + eles.map(ele => ele.hidden = hideSource); + const moveHandler = (e: PointerEvent) => { e.stopPropagation(); e.preventDefault(); - x += e.movementX; - y += e.movementY; if (dragData instanceof DocumentDragData) dragData.aliasOnDrop = e.ctrlKey || e.altKey; if (e.shiftKey) { abortDrag(); - CollectionDockingView.Instance.StartOtherDrag(doc, { pageX: e.pageX, pageY: e.pageY, preventDefault: () => { }, button: 0 }); + CollectionDockingView.Instance.StartOtherDrag(docs, { pageX: e.pageX, pageY: e.pageY, preventDefault: () => { }, button: 0 }); } - dragElement.style.transform = `translate(${x}px, ${y}px) scale(${scaleX}, ${scaleY})`; + dragElements.map((dragElement, i) => dragElement.style.transform = `translate(${xs[i] += e.movementX}px, ${ys[i] += e.movementY}px) scale(${scaleXs[i]}, ${scaleYs[i]})`); }; const abortDrag = () => { document.removeEventListener("pointermove", moveHandler, true); document.removeEventListener("pointerup", upHandler); - dragDiv.removeChild(dragElement); - ele.hidden = false; + dragElements.map(dragElement => dragDiv.removeChild(dragElement)); + eles.map(ele => ele.hidden = false); } const upHandler = (e: PointerEvent) => { abortDrag(); - FinishDrag(ele, e, dragData, options, finishDrag); + FinishDrag(eles, e, dragData, options, finishDrag); }; document.addEventListener("pointermove", moveHandler, true); document.addEventListener("pointerup", upHandler); } - function FinishDrag(dragEle: HTMLElement, e: PointerEvent, dragData: { [index: string]: any }, options?: DragOptions, finishDrag?: (dragData: { [index: string]: any }) => void) { - let parent = dragEle.parentElement; - if (parent) - parent.removeChild(dragEle); + function FinishDrag(dragEles: HTMLElement[], e: PointerEvent, dragData: { [index: string]: any }, options?: DragOptions, finishDrag?: (dragData: { [index: string]: any }) => void) { + let removed = dragEles.map(dragEle => { + let parent = dragEle.parentElement; + if (parent) + parent.removeChild(dragEle); + return [dragEle, parent]; + }); const target = document.elementFromPoint(e.x, e.y); - if (parent) - parent.appendChild(dragEle); - if (!target) { - return; - } - if (finishDrag) - finishDrag(dragData); - - target.dispatchEvent(new CustomEvent("dashOnDrop", { - bubbles: true, - detail: { - x: e.x, - y: e.y, - data: dragData + removed.map(r => { + let dragEle: HTMLElement = r[0]!; + let parent: HTMLElement | null = r[1]; + if (parent) + parent.appendChild(dragEle); + }); + if (target) { + if (finishDrag) + finishDrag(dragData); + + target.dispatchEvent(new CustomEvent("dashOnDrop", { + bubbles: true, + detail: { + x: e.x, + y: e.y, + data: dragData + } + })); + + if (options) { + options.handlers.dragComplete({}); } - })); - - if (options) { - options.handlers.dragComplete({}); } DocumentDecorations.Instance.Hidden = false; } diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss index 11595aa01..7a43f3087 100644 --- a/src/client/views/DocumentDecorations.scss +++ b/src/client/views/DocumentDecorations.scss @@ -32,6 +32,12 @@ } } +.documentDecorations-background { + background:lightblue; + position: absolute; + opacity: 0.1; +} + // position: absolute; // display: grid; // z-index: 1000; diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 47098c3b5..faba3b6ea 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -1,14 +1,14 @@ -import { observable, computed, action } from "mobx"; -import React = require("react"); -import { SelectionManager } from "../util/SelectionManager"; +import { action, computed, observable, trace } from "mobx"; import { observer } from "mobx-react"; -import './DocumentDecorations.scss' -import { KeyStore } from '../../fields/KeyStore' +import { KeyStore } from '../../fields/KeyStore'; +import { ListField } from "../../fields/ListField"; import { NumberField } from "../../fields/NumberField"; -import { props } from "bluebird"; import { DragManager } from "../util/DragManager"; +import { SelectionManager } from "../util/SelectionManager"; +import { CollectionView } from "./collections/CollectionView"; +import './DocumentDecorations.scss'; import { LinkMenu } from "./nodes/LinkMenu"; -import { ListField } from "../../fields/ListField"; +import React = require("react"); const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; @@ -22,6 +22,7 @@ export class DocumentDecorations extends React.Component { private _resizeBorderWidth = 16; private _linkButton = React.createRef(); @observable private _hidden = false; + @observable private _dragging = false; constructor(props: Readonly<{}>) { super(props) @@ -50,6 +51,50 @@ export class DocumentDecorations extends React.Component { public get Hidden() { return this._hidden; } public set Hidden(value: boolean) { this._hidden = value; } + _lastDrag: number[] = [0, 0]; + onBackgroundDown = (e: React.PointerEvent): void => { + document.removeEventListener("pointermove", this.onBackgroundMove); + document.addEventListener("pointermove", this.onBackgroundMove); + document.removeEventListener("pointerup", this.onBackgroundUp); + document.addEventListener("pointerup", this.onBackgroundUp); + this._lastDrag = [e.clientX, e.clientY] + e.stopPropagation(); + e.preventDefault(); + } + + @action + onBackgroundMove = (e: PointerEvent): void => { + let dragDocView = SelectionManager.SelectedDocuments()[0]; + const [left, top] = dragDocView.props.ScreenToLocalTransform().inverse().transformPoint(0, 0); + let dragData = new DragManager.DocumentDragData(SelectionManager.SelectedDocuments().map(dv => dv.props.Document)); + dragData.aliasOnDrop = false; + dragData.xOffset = e.x - left; + dragData.yOffset = e.y - top; + dragData.removeDocument = (dropCollectionView: CollectionView) => + dragData.draggedDocuments.map(d => { + if (dragDocView.props.RemoveDocument && dragDocView.props.ContainingCollectionView !== dropCollectionView) { + dragDocView.props.RemoveDocument(d); + } + }); + this._dragging = true; + document.removeEventListener("pointermove", this.onBackgroundMove); + document.removeEventListener("pointerup", this.onBackgroundUp); + DragManager.StartDocumentDrag(SelectionManager.SelectedDocuments().map(docView => (docView as any)._mainCont!.current!), dragData, { + handlers: { + dragComplete: action(() => this._dragging = false), + }, + hideSource: true + }) + e.stopPropagation(); + } + + onBackgroundUp = (e: PointerEvent): void => { + document.removeEventListener("pointermove", this.onBackgroundMove); + document.removeEventListener("pointerup", this.onBackgroundUp); + e.stopPropagation(); + e.preventDefault(); + } + onPointerDown = (e: React.PointerEvent): void => { e.stopPropagation(); if (e.button === 0) { @@ -191,7 +236,6 @@ export class DocumentDecorations extends React.Component { // buttonOnPointerUp = (e: React.PointerEvent): void => { // e.stopPropagation(); // } - render() { var bounds = this.Bounds; if (this.Hidden) { @@ -218,25 +262,36 @@ export class DocumentDecorations extends React.Component { ); } return ( -
-
e.preventDefault()}>
-
e.preventDefault()}>
-
e.preventDefault()}>
-
e.preventDefault()}>
-
-
e.preventDefault()}>
-
e.preventDefault()}>
-
e.preventDefault()}>
-
e.preventDefault()}>
- -
{linkButton}
- -
+
+
1 ? 1000 : 0, + }} onPointerDown={this.onBackgroundDown} onContextMenu={(e: React.MouseEvent) => { e.preventDefault(); e.stopPropagation() }} > +
+
+
e.preventDefault()}>
+
e.preventDefault()}>
+
e.preventDefault()}>
+
e.preventDefault()}>
+
+
e.preventDefault()}>
+
e.preventDefault()}>
+
e.preventDefault()}>
+
e.preventDefault()}>
+ +
{linkButton}
+ +
+
) } } \ No newline at end of file diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index 75855c3d1..6f66f8f38 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -218,7 +218,8 @@ export class Main extends React.Component { focusDocument = (doc: Document) => { } noScaling = () => 1; - get content() { + @computed + get mainContent() { return !this.mainContainer ? (null) : + runInAction(() => { this.pwidth = r.entry.width; this.pheight = r.entry.height; })}> {({ measureRef }) =>
- {this.content} + {this.mainContent}
}
- {this.nodesMenu} {this.miscButtons} diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index f123149dd..c6cbc05e7 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -47,9 +47,10 @@ export class CollectionDockingView extends React.Component { }, button: 0 }) + public StartOtherDrag(dragDocs: Document[], e: any) { + dragDocs.map(dragDoc => + this.AddRightSplit(dragDoc, true).contentItems[0].tab._dragListener. + onMouseDown({ pageX: e.pageX, pageY: e.pageY, preventDefault: () => { }, button: 0 })); } @action @@ -199,7 +200,7 @@ export class CollectionDockingView extends React.Component) => { if (f instanceof Document) - DragManager.StartDocumentDrag(tab, new DragManager.DocumentDragData(f as Document), + DragManager.StartDocumentDrag([tab], new DragManager.DocumentDragData([f as Document]), { handlers: { dragComplete: action(() => { }), @@ -265,6 +266,7 @@ export class CollectionDockingView extends React.Component { } render() { + trace(); if (!this._document) return (null); var content = diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index a1498e0ae..014aa1d8f 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -113,7 +113,7 @@ export class CollectionView extends React.Component { if (index !== -1) { value.splice(index, 1) - SelectionManager.DeselectAll() + //SelectionManager.DeselectAll() ContextMenu.Instance.clearItems() return true; } diff --git a/src/client/views/collections/CollectionViewBase.tsx b/src/client/views/collections/CollectionViewBase.tsx index 987f3cb6c..316d20c9d 100644 --- a/src/client/views/collections/CollectionViewBase.tsx +++ b/src/client/views/collections/CollectionViewBase.tsx @@ -82,9 +82,9 @@ export class CollectionViewBase extends React.Component if (de.data instanceof DragManager.DocumentDragData) { if (de.data.aliasOnDrop) { [KeyStore.Width, KeyStore.Height, KeyStore.CurPage].map(key => - de.data.draggedDocument.GetTAsync(key, NumberField, (f: Opt) => f ? de.data.droppedDocument.SetNumber(key, f.Data) : null)); + de.data.draggedDocuments.GetTAsync(key, NumberField, (f: Opt) => f ? de.data.droppedDocument.SetNumber(key, f.Data) : null)); } - let added = this.props.addDocument(de.data.droppedDocument, false); + let added = de.data.droppedDocuments.reduce((added, d) => this.props.addDocument(d, false), true); if (added && de.data.removeDocument && !de.data.aliasOnDrop) { de.data.removeDocument(this.props.CollectionView); } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 60fb95ff5..c5178f69d 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -77,13 +77,20 @@ export class CollectionFreeFormView extends CollectionViewBase { let screenX = de.x - (de.data.xOffset as number || 0); let screenY = de.y - (de.data.yOffset as number || 0); const [x, y] = this.getTransform().transformPoint(screenX, screenY); - de.data.droppedDocument.SetNumber(KeyStore.X, x); - de.data.droppedDocument.SetNumber(KeyStore.Y, y); - if (!de.data.droppedDocument.GetNumber(KeyStore.Width, 0)) { - de.data.droppedDocument.SetNumber(KeyStore.Width, 300); - de.data.droppedDocument.SetNumber(KeyStore.Height, 300); - } - this.bringToFront(de.data.droppedDocument); + let dragDoc = de.data.draggedDocuments[0]; + let dragX = dragDoc.GetNumber(KeyStore.X, 0); + let dragY = dragDoc.GetNumber(KeyStore.Y, 0); + de.data.draggedDocuments.map(d => { + let docX = d.GetNumber(KeyStore.X, 0); + let docY = d.GetNumber(KeyStore.Y, 0); + d.SetNumber(KeyStore.X, x + (docX - dragX)); + d.SetNumber(KeyStore.Y, y + (docY - dragY)); + if (!d.GetNumber(KeyStore.Width, 0)) { + d.SetNumber(KeyStore.Width, 300); + d.SetNumber(KeyStore.Height, 300); + } + this.bringToFront(d); + }) } return true; } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 71613ca4f..1195128dc 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -106,7 +106,7 @@ export class DocumentView extends React.Component { if (this.props.isTopMost) { this.startDragging(e.pageX, e.pageY, e.altKey || e.ctrlKey); } - else CollectionDockingView.Instance.StartOtherDrag(this.props.Document, e); + else CollectionDockingView.Instance.StartOtherDrag([this.props.Document], e); e.stopPropagation(); } else { if (this.active && !e.isDefaultPrevented()) { @@ -125,9 +125,7 @@ export class DocumentView extends React.Component { if (this._mainCont.current) { this.dropDisposer = DragManager.MakeDropTarget(this._mainCont.current, { handlers: { drop: this.drop.bind(this) } }); } - runInAction(() => { - DocumentManager.Instance.DocumentViews.push(this); - }) + runInAction(() => DocumentManager.Instance.DocumentViews.push(this)) this._reactionDisposer = reaction( () => this.props.ContainingCollectionView && this.props.ContainingCollectionView.SelectedDocs.slice(), () => { @@ -149,10 +147,7 @@ export class DocumentView extends React.Component { if (this.dropDisposer) { this.dropDisposer(); } - runInAction(() => { - DocumentManager.Instance.DocumentViews.splice(DocumentManager.Instance.DocumentViews.indexOf(this), 1); - - }) + runInAction(() => DocumentManager.Instance.DocumentViews.splice(DocumentManager.Instance.DocumentViews.indexOf(this), 1)) if (this._reactionDisposer) { this._reactionDisposer(); } @@ -161,7 +156,7 @@ export class DocumentView extends React.Component { startDragging(x: number, y: number, dropAliasOfDraggedDoc: boolean) { if (this._mainCont.current) { const [left, top] = this.props.ScreenToLocalTransform().inverse().transformPoint(0, 0); - let dragData = new DragManager.DocumentDragData(this.props.Document); + let dragData = new DragManager.DocumentDragData([this.props.Document]); dragData.aliasOnDrop = dropAliasOfDraggedDoc; dragData.xOffset = x - left; dragData.yOffset = y - top; @@ -170,7 +165,7 @@ export class DocumentView extends React.Component { this.props.RemoveDocument(this.props.Document); } } - DragManager.StartDocumentDrag(this._mainCont.current, dragData, { + DragManager.StartDocumentDrag([this._mainCont.current], dragData, { handlers: { dragComplete: action(() => { }), }, -- cgit v1.2.3-70-g09d2 From 5889bf159ee0a0f6567683b2bb8c2475feccf9ec Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Wed, 3 Apr 2019 01:38:29 -0400 Subject: Almost compiles --- src/Utils.ts | 10 ++++++ src/client/Server.ts | 2 +- src/client/documents/Documents.ts | 3 +- src/client/northstar/dash-nodes/HistogramBox.tsx | 14 ++++---- src/client/util/DragManager.ts | 2 +- src/client/util/Transform.ts | 2 +- src/client/util/type_decls.d | 2 +- src/client/views/Main.tsx | 10 +++--- .../views/collections/CollectionBaseView.tsx | 28 +++++++++++++--- .../views/collections/CollectionDockingView.tsx | 9 ++--- src/client/views/collections/CollectionPDFView.tsx | 36 ++++++++++---------- .../views/collections/CollectionSchemaView.tsx | 12 +++++-- .../views/collections/CollectionTreeView.tsx | 3 +- .../views/collections/CollectionVideoView.tsx | 39 +++++++++++----------- src/client/views/collections/CollectionView.tsx | 4 +-- .../views/collections/CollectionViewBase.tsx | 7 ++-- .../CollectionFreeFormRemoteCursors.tsx | 17 ++-------- .../collectionFreeForm/CollectionFreeFormView.tsx | 30 +++++++++++------ src/client/views/nodes/DocumentContentsView.tsx | 18 +++++++++- src/client/views/nodes/DocumentView.tsx | 37 +++++++++----------- src/client/views/nodes/FieldView.tsx | 17 ++++++---- src/client/views/nodes/KeyValuePair.tsx | 4 +++ src/fields/Field.ts | 4 +-- 23 files changed, 181 insertions(+), 129 deletions(-) (limited to 'src/client/northstar') diff --git a/src/Utils.ts b/src/Utils.ts index a5d9bd0ca..3eb192eb8 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -86,4 +86,14 @@ export class Utils { } } +export function returnTrue() { + return true; +} + +export function returnFalse() { + return false; +} + +export function emptyFunction() { } + export type Without = Pick>; \ No newline at end of file diff --git a/src/client/Server.ts b/src/client/Server.ts index 37e3c2c0d..c301b04d3 100644 --- a/src/client/Server.ts +++ b/src/client/Server.ts @@ -42,7 +42,7 @@ export class Server { reaction(() => { return this.ClientFieldsCached.get(fieldid); }, (field, reaction) => { - if (field !== "") { + if (field !== FieldWaiting) { reaction.dispose() cb(field) } diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 0bf275df8..15f980895 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -17,7 +17,8 @@ import { HistogramOperation } from "../northstar/operations/HistogramOperation"; import { Server } from "../Server"; import { CollectionPDFView } from "../views/collections/CollectionPDFView"; import { CollectionVideoView } from "../views/collections/CollectionVideoView"; -import { CollectionView, CollectionViewType } from "../views/collections/CollectionView"; +import { CollectionView } from "../views/collections/CollectionView"; +import { CollectionViewType } from "../views/collections/CollectionBaseView"; import { AudioBox } from "../views/nodes/AudioBox"; import { FormattedTextBox } from "../views/nodes/FormattedTextBox"; import { ImageBox } from "../views/nodes/ImageBox"; diff --git a/src/client/northstar/dash-nodes/HistogramBox.tsx b/src/client/northstar/dash-nodes/HistogramBox.tsx index a968def96..4457c9502 100644 --- a/src/client/northstar/dash-nodes/HistogramBox.tsx +++ b/src/client/northstar/dash-nodes/HistogramBox.tsx @@ -117,14 +117,14 @@ export class HistogramBox extends React.Component { activateHistogramOperation(catalog?: Catalog) { if (catalog) { - this.props.doc.GetTAsync(this.props.fieldKey, HistogramField).then((histoOp: Opt) => runInAction(() => { + this.props.Document.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.Links.splice(0, this.HistoOp.Links.length, ...docs), { fireImmediately: true }); - reaction(() => this.props.doc.GetList(KeyStore.BrushingDocs, []).length, + reaction(() => this.props.Document.GetList(KeyStore.LinkedFromDocs, []), (docs: Document[]) => this.HistoOp.Links.splice(0, this.HistoOp.Links.length, ...docs), { fireImmediately: true }); + reaction(() => this.props.Document.GetList(KeyStore.BrushingDocs, []).length, () => { - let brushingDocs = this.props.doc.GetList(KeyStore.BrushingDocs, [] as Document[]); - let proto = this.props.doc.GetPrototype() as Document; + let brushingDocs = this.props.Document.GetList(KeyStore.BrushingDocs, [] as Document[]); + let proto = this.props.Document.GetPrototype() as Document; 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[]); @@ -139,8 +139,8 @@ export class HistogramBox extends React.Component { 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); + var h = this.props.isTopMost ? this.PanelHeight : this.props.Document.GetNumber(KeyStore.Height, 0); + var w = this.props.isTopMost ? this.PanelWidth : this.props.Document.GetNumber(KeyStore.Width, 0); let loff = this.SizeConverter.LeftOffset; let toff = this.SizeConverter.TopOffset; let roff = this.SizeConverter.RightOffset; diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 70b1c9829..53bbae18d 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -110,7 +110,7 @@ export namespace DragManager { xOffset?: number; yOffset?: number; aliasOnDrop?: boolean; - removeDocument?: (collectionDrop: CollectionView) => void; + moveDocument?: (targetCollection: Document, addDocument: (document: Document) => void) => void; [id: string]: any; } export function StartDocumentDrag(ele: HTMLElement, dragData: DocumentDragData, options?: DragOptions) { diff --git a/src/client/util/Transform.ts b/src/client/util/Transform.ts index 3e1039166..889134e3e 100644 --- a/src/client/util/Transform.ts +++ b/src/client/util/Transform.ts @@ -3,7 +3,7 @@ export class Transform { private _translateY: number = 0; private _scale: number = 1; - static get Identity(): Transform { + static Identity(): Transform { return new Transform(0, 0, 1); } diff --git a/src/client/util/type_decls.d b/src/client/util/type_decls.d index 4f69053b1..47c3481b2 100644 --- a/src/client/util/type_decls.d +++ b/src/client/util/type_decls.d @@ -181,7 +181,7 @@ declare class Key extends Field { Copy(): Field; ToScriptString(): string; } -declare type FIELD_WAITING = ""; +declare type FIELD_WAITING = null; declare type Opt = T | undefined; declare type FieldValue = Opt | FIELD_WAITING; // @ts-ignore diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index 82fd1e7c9..bcbe6b987 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -6,7 +6,7 @@ import { Document } from '../../fields/Document'; import { KeyStore } from '../../fields/KeyStore'; import "./Main.scss"; import { MessageStore } from '../../server/Message'; -import { Utils } from '../../Utils'; +import { Utils, returnTrue } from '../../Utils'; import * as request from 'request' import * as rp from 'request-promise' import { Documents } from '../documents/Documents'; @@ -212,7 +212,6 @@ export class Main extends React.Component { this.workspacesShown = !this.workspacesShown; } - screenToLocalTransform = () => Transform.Identity pwidthFunc = () => this.pwidth; pheightFunc = () => this.pheight; focusDocument = (doc: Document) => { } @@ -221,15 +220,16 @@ export class Main extends React.Component { get content() { return !this.mainContainer ? (null) : } diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx index c8c840085..c9f640c4a 100644 --- a/src/client/views/collections/CollectionBaseView.tsx +++ b/src/client/views/collections/CollectionBaseView.tsx @@ -19,16 +19,21 @@ export enum CollectionViewType { } export interface CollectionRenderProps { - addDocument: (document: Document, allowDuplicates: boolean) => void; + addDocument: (document: Document, allowDuplicates?: boolean) => boolean; removeDocument: (document: Document) => boolean; + moveDocument: (document: Document, targetCollection: Document, addDocument: (document: Document) => void) => boolean; active: () => boolean; } export interface CollectionViewProps extends FieldViewProps { onContextMenu?: (e: React.MouseEvent) => void; - children: (type: CollectionViewType, props: CollectionRenderProps) => JSX.Element | null; + children: (type: CollectionViewType, props: CollectionRenderProps) => JSX.Element | JSX.Element[] | null; + className?: string; + contentRef?: React.Ref; } +export const COLLECTION_BORDER_WIDTH = 1; + export class CollectionBaseView extends React.Component { get collectionViewType(): CollectionViewType { let Document = this.props.Document; @@ -44,7 +49,7 @@ export class CollectionBaseView extends React.Component { active = (): boolean => { var isSelected = this.props.isSelected(); - var childSelected = SelectionManager.SelectedDocuments().some(view => view.props.ContainingCollectionView == self); + var childSelected = SelectionManager.SelectedDocuments().some(view => view.props.ContainingCollectionView == this); var topMost = this.props.isTopMost; return isSelected || childSelected || topMost; } @@ -68,7 +73,7 @@ export class CollectionBaseView extends React.Component { } @action.bound - addDocument(doc: Document, allowDuplicates: boolean): boolean { + addDocument(doc: Document, allowDuplicates: boolean = false): boolean { let props = this.props; var curPage = props.Document.GetNumber(KeyStore.CurPage, -1); doc.SetOnPrototype(KeyStore.Page, new NumberField(curPage)); @@ -123,14 +128,27 @@ export class CollectionBaseView extends React.Component { return false } + @action.bound + moveDocument(doc: Document, targetCollection: Document, addDocument: (doc: Document) => void): boolean { + if (this.props.Document === targetCollection) { + return false; + } + if (this.removeDocument(doc)) { + addDocument(doc); + return true; + } + return false; + } + render() { const props: CollectionRenderProps = { addDocument: this.addDocument, removeDocument: this.removeDocument, + moveDocument: this.moveDocument, active: this.active } return ( -
+
{this.props.children(this.collectionViewType, props)}
) diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index c67354139..bb34340fb 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -8,12 +8,12 @@ import { Document } from "../../../fields/Document"; import { KeyStore } from "../../../fields/KeyStore"; import Measure from "react-measure"; import { FieldId, Opt, Field } from "../../../fields/Field"; -import { Utils } from "../../../Utils"; +import { Utils, returnTrue } from "../../../Utils"; import { Server } from "../../Server"; import { undoBatch } from "../../util/UndoManager"; import { DocumentView } from "../nodes/DocumentView"; import "./CollectionDockingView.scss"; -import { COLLECTION_BORDER_WIDTH } from "./CollectionView"; +import { COLLECTION_BORDER_WIDTH } from "./CollectionBaseView"; import React = require("react"); import { SubCollectionViewProps } from "./CollectionViewBase"; import { ServerUtils } from "../../../server/ServerUtil"; @@ -310,14 +310,15 @@ export class DockedFrameRenderer extends React.Component { var content =
{ }} ContainingCollectionView={undefined} />
diff --git a/src/client/views/collections/CollectionPDFView.tsx b/src/client/views/collections/CollectionPDFView.tsx index 6bb3bacc7..14ed70b8c 100644 --- a/src/client/views/collections/CollectionPDFView.tsx +++ b/src/client/views/collections/CollectionPDFView.tsx @@ -1,23 +1,20 @@ import { action, computed, observable } from "mobx"; import { observer } from "mobx-react"; -import { Document } from "../../../fields/Document"; import { KeyStore } from "../../../fields/KeyStore"; import { ContextMenu } from "../ContextMenu"; -import { CollectionView, CollectionViewType } from "./CollectionView"; import { CollectionViewProps } from "./CollectionViewBase"; import "./CollectionPDFView.scss" import React = require("react"); -import { FieldId } from "../../../fields/Field"; import { CollectionFreeFormView } from "./collectionFreeForm/CollectionFreeFormView"; +import { FieldView } from "../nodes/FieldView"; +import { CollectionRenderProps, CollectionBaseView, CollectionViewType } from "./CollectionBaseView"; @observer export class CollectionPDFView extends React.Component { public static LayoutString(fieldKey: string = "DataKey") { - return `<${CollectionPDFView.name} Document={Document} - ScreenToLocalTransform={ScreenToLocalTransform} fieldKey={${fieldKey}} panelWidth={PanelWidth} panelHeight={PanelHeight} isSelected={isSelected} select={select} bindings={bindings} - isTopMost={isTopMost} SelectOnLoad={selectOnLoad} BackgroundView={BackgroundView} focus={focus}/>`; + return FieldView.LayoutString(CollectionPDFView, fieldKey); } private get curPage() { return this.props.Document.GetNumber(KeyStore.CurPage, -1); } @@ -35,26 +32,27 @@ export class CollectionPDFView extends React.Component { ); } - // "inherited" CollectionView API starts here... - @observable - public SelectedDocs: FieldId[] = [] - public active: () => boolean = () => CollectionView.Active(this); - - addDocument = (doc: Document, allowDuplicates: boolean): boolean => { return CollectionView.AddDocument(this.props, doc, allowDuplicates); } - removeDocument = (doc: Document): boolean => { return CollectionView.RemoveDocument(this.props, doc); } - - specificContextMenu = (e: React.MouseEvent): void => { + onContextMenu = (e: React.MouseEvent): void => { if (!e.isPropagationStopped() && this.props.Document.Id != "mainDoc") { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 ContextMenu.Instance.addItem({ description: "PDFOptions", event: () => { } }); } } - render() { + private subView = (_type: CollectionViewType, renderProps: CollectionRenderProps) => { + let props = { ...renderProps, ...this.props }; return ( -
- + <> + {this.props.isSelected() ? this.uIButtons : (null)} -
+ + ) + } + + render() { + return ( + + {this.subView} + ) } } \ No newline at end of file diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index 0c7e28691..0eacd38b0 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -22,9 +22,11 @@ import { EditableView } from "../EditableView"; import { DocumentView } from "../nodes/DocumentView"; import { FieldView, FieldViewProps } from "../nodes/FieldView"; import "./CollectionSchemaView.scss"; -import { CollectionView, COLLECTION_BORDER_WIDTH } from "./CollectionView"; +import { CollectionView } from "./CollectionView"; import { CollectionViewBase } from "./CollectionViewBase"; import { TextField } from "../../../fields/TextField"; +import { COLLECTION_BORDER_WIDTH } from "./CollectionBaseView"; +import { emptyFunction, returnFalse } from "../../../Utils"; // bcz: need to add drag and drop of rows and columns. This seems like it might work for rows: https://codesandbox.io/s/l94mn1q657 @@ -79,6 +81,9 @@ export class CollectionSchemaView extends CollectionViewBase { select: () => { }, isTopMost: false, selectOnLoad: false, + ScreenToLocalTransform: Transform.Identity, + focus: emptyFunction, + active: returnFalse } let contents = ( @@ -295,15 +300,16 @@ export class CollectionSchemaView extends CollectionViewBase { {({ measureRef }) =>
{doc instanceof Document ? : null} diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 70790af18..6f9ba40d2 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -10,9 +10,10 @@ import { ListField } from "../../../fields/ListField"; import { setupDrag } from "../../util/DragManager"; import { EditableView } from "../EditableView"; import "./CollectionTreeView.scss"; -import { CollectionView, COLLECTION_BORDER_WIDTH } from "./CollectionView"; +import { CollectionView } from "./CollectionView"; import { CollectionViewBase } from "./CollectionViewBase"; import React = require("react") +import { COLLECTION_BORDER_WIDTH } from './CollectionBaseView'; export interface TreeViewProps { diff --git a/src/client/views/collections/CollectionVideoView.tsx b/src/client/views/collections/CollectionVideoView.tsx index 1f0143d87..7cb461b4d 100644 --- a/src/client/views/collections/CollectionVideoView.tsx +++ b/src/client/views/collections/CollectionVideoView.tsx @@ -3,12 +3,14 @@ import { observer } from "mobx-react"; import { Document } from "../../../fields/Document"; import { KeyStore } from "../../../fields/KeyStore"; import { ContextMenu } from "../ContextMenu"; -import { CollectionView, CollectionViewType } from "./CollectionView"; +import { CollectionView } from "./CollectionView"; +import { CollectionViewType, CollectionBaseView, CollectionRenderProps } from "./CollectionBaseView"; import { CollectionViewProps } from "./CollectionViewBase"; import React = require("react"); import { FieldId } from "../../../fields/Field"; import "./CollectionVideoView.scss" -import { CollectionFreeFormView } from "./CollectionFreeFormView"; +import { CollectionFreeFormView } from "./collectionFreeForm/CollectionFreeFormView"; +import { FieldView } from "../nodes/FieldView"; @observer @@ -20,9 +22,7 @@ export class CollectionVideoView extends React.Component { @observable _isPlaying: boolean = false; public static LayoutString(fieldKey: string = "DataKey") { - return `<${CollectionVideoView.name} Document={Document} - ScreenToLocalTransform={ScreenToLocalTransform} fieldKey={${fieldKey}} panelWidth={PanelWidth} panelHeight={PanelHeight} isSelected={isSelected} select={select} bindings={bindings} - isTopMost={isTopMost} SelectOnLoad={selectOnLoad} BackgroundView={BackgroundView} focus={focus}/>`; + return FieldView.LayoutString(CollectionVideoView, fieldKey); } private get uIButtons() { let scaling = Math.min(1.8, this.props.ScreenToLocalTransform().transformDirection(1, 1)[0]); @@ -102,26 +102,27 @@ export class CollectionVideoView extends React.Component { } - // "inherited" CollectionView API starts here... - - @observable - public SelectedDocs: FieldId[] = [] - public active: () => boolean = () => CollectionView.Active(this); - - addDocument = (doc: Document, allowDuplicates: boolean): boolean => { return CollectionView.AddDocument(this.props, doc, allowDuplicates); } - removeDocument = (doc: Document): boolean => { return CollectionView.RemoveDocument(this.props, doc); } - - specificContextMenu = (e: React.MouseEvent): void => { + onContextMenu = (e: React.MouseEvent): void => { if (!e.isPropagationStopped() && this.props.Document.Id != "mainDoc") { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 ContextMenu.Instance.addItem({ description: "VideoOptions", event: () => { } }); } } + private subView = (_type: CollectionViewType, renderProps: CollectionRenderProps) => { + let props = { ...renderProps, ...this.props }; + return ( + <> + + {this.props.isSelected() ? this.uIButtons : (null)} + + ) + } + render() { trace(); - return (
- - {this.props.isSelected() ? this.uIButtons : (null)} -
) + return ( + + {this.subView} + ) } } \ No newline at end of file diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 51cc99595..d440dcff9 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -12,7 +12,7 @@ export class CollectionView extends React.Component { public static LayoutString(fieldStr: string = "DataKey") { return FieldView.LayoutString(CollectionView, fieldStr) } private SubView = (type: CollectionViewType, renderProps: CollectionRenderProps) => { - let props = { ...renderProps, ...this.props }; + let props = { ...this.props, ...renderProps }; switch (type) { case CollectionViewType.Freeform: return () case CollectionViewType.Schema: return () @@ -34,7 +34,7 @@ export class CollectionView extends React.Component { return ( {this.SubView} - > + ) } } \ No newline at end of file diff --git a/src/client/views/collections/CollectionViewBase.tsx b/src/client/views/collections/CollectionViewBase.tsx index ca4f3b12f..4a0b2312e 100644 --- a/src/client/views/collections/CollectionViewBase.tsx +++ b/src/client/views/collections/CollectionViewBase.tsx @@ -20,6 +20,9 @@ import { Server } from "../../Server"; import { FieldViewProps } from "../nodes/FieldView"; export interface CollectionViewProps extends FieldViewProps { + addDocument: (document: Document, allowDuplicates?: boolean) => boolean; + removeDocument: (document: Document) => boolean; + moveDocument: (document: Document, targetCollection: Document, addDocument: (document: Document) => void) => boolean; } export interface SubCollectionViewProps extends CollectionViewProps { @@ -72,8 +75,8 @@ export class CollectionViewBase extends React.Component de.data.draggedDocument.GetTAsync(key, NumberField, (f: Opt) => f ? de.data.droppedDocument.SetNumber(key, f.Data) : null)); } let added = this.props.addDocument(de.data.droppedDocument, false); - if (added && de.data.removeDocument && !de.data.aliasOnDrop) { - de.data.removeDocument(this.props.CollectionView); + if (added && de.data.moveDocument && !de.data.aliasOnDrop) { + de.data.moveDocument(this.props.Document, this.props.addDocument); } e.stopPropagation(); return added; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx index 19382e66f..f664f4e65 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx @@ -1,21 +1,8 @@ -import { action, computed, observable } from "mobx"; +import { computed } from "mobx"; import { observer } from "mobx-react"; -import { Document } from "../../../../fields/Document"; -import { FieldWaiting } from "../../../../fields/Field"; import { KeyStore } from "../../../../fields/KeyStore"; -import { TextField } from "../../../../fields/TextField"; -import { DragManager } from "../../../util/DragManager"; -import { Transform } from "../../../util/Transform"; -import { undoBatch } from "../../../util/UndoManager"; -import { InkingCanvas } from "../../InkingCanvas"; -import { CollectionFreeFormDocumentView } from "../../nodes/CollectionFreeFormDocumentView"; -import { DocumentContentsView } from "../../nodes/DocumentContentsView"; -import { DocumentViewProps } from "../../nodes/DocumentView"; -import { COLLECTION_BORDER_WIDTH } from "../CollectionView"; -import { CollectionViewBase, CollectionViewProps, CursorEntry } from "../CollectionViewBase"; -import { CollectionFreeFormLinksView } from "./CollectionFreeFormLinksView"; +import { CollectionViewProps, CursorEntry } from "../CollectionViewBase"; import "./CollectionFreeFormView.scss"; -import { MarqueeView } from "./MarqueeView"; import React = require("react"); import v5 = require("uuid/v5"); import { CurrentUserUtils } from "../../../../server/authentication/models/current_user_utils"; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 51ab85b71..144d121db 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -11,7 +11,7 @@ import { InkingCanvas } from "../../InkingCanvas"; import { CollectionFreeFormDocumentView } from "../../nodes/CollectionFreeFormDocumentView"; import { DocumentContentsView } from "../../nodes/DocumentContentsView"; import { DocumentViewProps } from "../../nodes/DocumentView"; -import { COLLECTION_BORDER_WIDTH } from "../CollectionView"; +import { COLLECTION_BORDER_WIDTH } from "../CollectionBaseView"; import { CollectionViewBase } from "../CollectionViewBase"; import { CollectionFreeFormLinksView } from "./CollectionFreeFormLinksView"; import "./CollectionFreeFormView.scss"; @@ -20,6 +20,8 @@ import React = require("react"); import v5 = require("uuid/v5"); import { CollectionFreeFormRemoteCursors } from "./CollectionFreeFormRemoteCursors"; import { PreviewCursor } from "./PreviewCursor"; +import { DocumentManager } from "../../../util/DocumentManager"; +import { SelectionManager } from "../../../util/SelectionManager"; @observer export class CollectionFreeFormView extends CollectionViewBase { @@ -39,8 +41,13 @@ export class CollectionFreeFormView extends CollectionViewBase { } public selectDocuments = (docs: Document[]) => { - this.props.CollectionView.SelectedDocs.length = 0; - docs.map(d => this.props.CollectionView.SelectedDocs.push(d.Id)); + SelectionManager.DeselectAll; + docs.map(doc => { + const dv = DocumentManager.Instance.getDocumentView(doc); + if (dv) { + SelectionManager.SelectDoc(dv, true); + } + }) } public getActiveDocuments = () => { @@ -59,6 +66,8 @@ export class CollectionFreeFormView extends CollectionViewBase { @observable private _lastX: number = 0; @observable private _lastY: number = 0; + private outerElement?: HTMLDivElement; + @computed get panX(): number { return this.props.Document.GetNumber(KeyStore.PanX, 0) } @computed get panY(): number { return this.props.Document.GetNumber(KeyStore.PanY, 0) } @computed get scale(): number { return this.props.Document.GetNumber(KeyStore.Scale, 1); } @@ -66,8 +75,8 @@ export class CollectionFreeFormView extends CollectionViewBase { @computed get nativeWidth() { return this.props.Document.GetNumber(KeyStore.NativeWidth, 0); } @computed get nativeHeight() { return this.props.Document.GetNumber(KeyStore.NativeHeight, 0); } @computed get zoomScaling() { return this.props.Document.GetNumber(KeyStore.Scale, 1); } - @computed get centeringShiftX() { return !this.props.Document.GetNumber(KeyStore.NativeWidth, 0) ? this.props.panelWidth() / 2 : 0; } // shift so pan position is at center of window for non-overlay collections - @computed get centeringShiftY() { return !this.props.Document.GetNumber(KeyStore.NativeHeight, 0) ? this.props.panelHeight() / 2 : 0; }// shift so pan position is at center of window for non-overlay collections + @computed get centeringShiftX() { return !this.props.Document.GetNumber(KeyStore.NativeWidth, 0) && this.outerElement ? this.outerElement.clientWidth / 2 : 0; } // shift so pan position is at center of window for non-overlay collections + @computed get centeringShiftY() { return !this.props.Document.GetNumber(KeyStore.NativeHeight, 0) && this.outerElement ? this.outerElement.clientHeight / 2 : 0; }// shift so pan position is at center of window for non-overlay collections @undoBatch @action @@ -227,16 +236,17 @@ export class CollectionFreeFormView extends CollectionViewBase { getDocumentViewProps(document: Document): DocumentViewProps { return { Document: document, - AddDocument: this.props.addDocument, - RemoveDocument: this.props.removeDocument, + addDocument: this.props.addDocument, + removeDocument: this.props.removeDocument, ScreenToLocalTransform: this.getTransform, isTopMost: false, selectOnLoad: document.Id == this._selectOnLoaded, PanelWidth: document.Width, PanelHeight: document.Height, ContentScaling: this.noScaling, - ContainingCollectionView: this.props.CollectionView, - focus: this.focusDocument + ContainingCollectionView: undefined, + focus: this.focusDocument, + parentActive: this.props.active, } } @@ -266,7 +276,7 @@ export class CollectionFreeFormView extends CollectionViewBase { getTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-COLLECTION_BORDER_WIDTH, -COLLECTION_BORDER_WIDTH).translate(-this.centeringShiftX, -this.centeringShiftY).transform(this.getLocalTransform()) getContainerTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-COLLECTION_BORDER_WIDTH, -COLLECTION_BORDER_WIDTH) - getLocalTransform = (): Transform => Transform.Identity.scale(1 / this.scale).translate(this.panX, this.panY); + getLocalTransform = (): Transform => Transform.Identity().scale(1 / this.scale).translate(this.panX, this.panY); noScaling = () => 1; childViews = () => this.views; diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index a5e4b1a17..2574b374a 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -44,7 +44,18 @@ export class DocumentContentsView extends React.Component; Document: Document; - AddDocument?: (doc: Document, allowDuplicates: boolean) => boolean; - RemoveDocument?: (doc: Document) => boolean; + addDocument?: (doc: Document, allowDuplicates?: boolean) => boolean; + removeDocument?: (doc: Document) => boolean; + moveDocument?: (doc: Document, targetCollection: Document, addDocument: (document: Document) => void) => boolean; ScreenToLocalTransform: () => Transform; isTopMost: boolean; ContentScaling: () => number; @@ -33,6 +35,7 @@ export interface DocumentViewProps { PanelHeight: () => number; focus: (doc: Document) => void; selectOnLoad: boolean; + parentActive: () => boolean; } export interface JsxArgs extends DocumentViewProps { Keys: { [name: string]: Key } @@ -83,9 +86,8 @@ export class DocumentView extends React.Component { private _mainCont = React.createRef(); private _downX: number = 0; private _downY: number = 0; - private _reactionDisposer: Opt; - @computed get active(): boolean { return SelectionManager.IsSelected(this) || !this.props.ContainingCollectionView || this.props.ContainingCollectionView.active(); } - @computed get topMost(): boolean { return !this.props.ContainingCollectionView || this.props.ContainingCollectionView.collectionViewType == CollectionViewType.Docking; } + @computed get active(): boolean { return SelectionManager.IsSelected(this) || this.props.parentActive(); } + @computed get topMost(): boolean { return this.props.isTopMost; } @computed get layout(): string { return this.props.Document.GetText(KeyStore.Layout, "

Error loading layout data

"); } @computed get layoutKeys(): Key[] { return this.props.Document.GetData(KeyStore.LayoutKeys, ListField, new Array()); } @computed get layoutFields(): Key[] { return this.props.Document.GetData(KeyStore.LayoutFields, ListField, new Array()); } @@ -119,12 +121,6 @@ export class DocumentView extends React.Component { runInAction(() => { DocumentManager.Instance.DocumentViews.push(this); }) - this._reactionDisposer = reaction( - () => this.props.ContainingCollectionView && this.props.ContainingCollectionView.SelectedDocs.slice(), - () => { - if (this.props.ContainingCollectionView && this.props.ContainingCollectionView.SelectedDocs.indexOf(this.props.Document.Id) != -1) - SelectionManager.SelectDoc(this, true); - }); } componentDidUpdate() { @@ -144,9 +140,6 @@ export class DocumentView extends React.Component { DocumentManager.Instance.DocumentViews.splice(DocumentManager.Instance.DocumentViews.indexOf(this), 1); }) - if (this._reactionDisposer) { - this._reactionDisposer(); - } } startDragging(x: number, y: number, dropAliasOfDraggedDoc: boolean) { @@ -156,9 +149,9 @@ export class DocumentView extends React.Component { dragData.aliasOnDrop = dropAliasOfDraggedDoc; dragData.xOffset = x - left; dragData.yOffset = y - top; - dragData.removeDocument = (dropCollectionView: CollectionView) => { - if (this.props.RemoveDocument && this.props.ContainingCollectionView !== dropCollectionView) { - this.props.RemoveDocument(this.props.Document); + dragData.moveDocument = (targetCollection: Document, addDocument: (document: Document) => void) => { + if (this.props.moveDocument) { + this.props.moveDocument(this.props.Document, targetCollection, addDocument) } } DragManager.StartDocumentDrag(this._mainCont.current, dragData, { @@ -197,14 +190,14 @@ export class DocumentView extends React.Component { } deleteClicked = (): void => { - if (this.props.RemoveDocument) { - this.props.RemoveDocument(this.props.Document); + if (this.props.removeDocument) { + this.props.removeDocument(this.props.Document); } } fieldsClicked = (e: React.MouseEvent): void => { - if (this.props.AddDocument) { - this.props.AddDocument(Documents.KVPDocument(this.props.Document, { width: 300, height: 300 }), false); + if (this.props.addDocument) { + this.props.addDocument(Documents.KVPDocument(this.props.Document, { width: 300, height: 300 }), false); } } fullScreenClicked = (e: React.MouseEvent): void => { diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index 2a7d3175f..57af55f9f 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -19,6 +19,7 @@ import { ListField } from "../../../fields/ListField"; import { DocumentContentsView } from "./DocumentContentsView"; import { Transform } from "../../util/Transform"; import { KeyStore } from "../../../fields/KeyStore"; +import { returnFalse } from "../../../Utils"; // @@ -33,8 +34,9 @@ export interface FieldViewProps { select: (isCtrlPressed: boolean) => void; isTopMost: boolean; selectOnLoad: boolean; - addDocument: (document: Document, allowDuplicates: boolean) => boolean; - removeDocument: (document: Document) => boolean; + addDocument?: (document: Document, allowDuplicates?: boolean) => boolean; + removeDocument?: (document: Document) => boolean; + moveDocument?: (document: Document, targetCollection: Document, addDocument: (document: Document) => void) => boolean; ScreenToLocalTransform: () => Transform; active: () => boolean; focus: (doc: Document) => void; @@ -73,19 +75,20 @@ export class FieldView extends React.Component { } else if (field instanceof Document) { return ( Transform.Identity} + addDocument={undefined} + removeDocument={undefined} + ScreenToLocalTransform={Transform.Identity} ContentScaling={() => 1} PanelWidth={() => 100} PanelHeight={() => 100} - isTopMost={true} + isTopMost={true} //TODO Why is this top most? selectOnLoad={false} focus={() => { }} isSelected={() => false} select={() => false} layoutKey={KeyStore.Layout} - ContainingCollectionView={undefined} />) + ContainingCollectionView={undefined} + parentActive={this.props.active} />) } else if (field instanceof ListField) { return (
diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx index 2fc11328f..e178cbc8d 100644 --- a/src/client/views/nodes/KeyValuePair.tsx +++ b/src/client/views/nodes/KeyValuePair.tsx @@ -11,6 +11,7 @@ import { Key } from '../../../fields/Key'; import { Server } from "../../Server" import { EditableView } from "../EditableView"; import { CompileScript, ToField } from "../../util/Scripting"; +import { Transform } from '../../util/Transform'; // Represents one row in a key value plane @@ -49,6 +50,9 @@ export class KeyValuePair extends React.Component { select: () => { }, isTopMost: false, selectOnLoad: false, + active: () => false, + ScreenToLocalTransform: Transform.Identity, + focus: () => { }, } let contents = ( diff --git a/src/fields/Field.ts b/src/fields/Field.ts index d48509a47..0d0e56f77 100644 --- a/src/fields/Field.ts +++ b/src/fields/Field.ts @@ -12,8 +12,8 @@ export function Cast(field: FieldValue, ctor: { new(): T return undefined; } -export const FieldWaiting: FIELD_WAITING = ""; -export type FIELD_WAITING = ""; +export const FieldWaiting: FIELD_WAITING = null; +export type FIELD_WAITING = null; export type FieldId = string; export type Opt = T | undefined; export type FieldValue = Opt | FIELD_WAITING; -- cgit v1.2.3-70-g09d2 From dc2a998acdae1545c8e7bf9ee9f4ca98bba82ac9 Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Thu, 4 Apr 2019 01:30:01 -0400 Subject: Started adding linting --- package.json | 2 + src/Utils.ts | 2 +- src/client/Server.ts | 52 +++++++------- src/client/SocketStub.ts | 2 +- src/client/northstar/manager/Gateway.ts | 24 +++---- src/client/util/DocumentManager.ts | 10 +-- src/client/util/DragManager.ts | 23 +++--- src/client/util/Scripting.ts | 14 ++-- src/client/util/SelectionManager.ts | 5 +- src/client/util/Transform.ts | 50 ++++++------- src/client/util/TypedEvent.ts | 5 +- src/client/util/UndoManager.ts | 4 +- src/client/views/DocumentDecorations.tsx | 2 +- src/client/views/EditableView.tsx | 4 +- src/client/views/InkingCanvas.tsx | 14 ++-- src/client/views/InkingControl.tsx | 4 +- src/client/views/InkingStroke.tsx | 7 +- src/client/views/Main.tsx | 13 ++-- .../views/collections/CollectionBaseView.tsx | 4 +- .../views/collections/CollectionSchemaView.tsx | 17 ++--- .../views/collections/CollectionVideoView.tsx | 2 +- .../views/collections/CollectionViewBase.tsx | 5 +- .../CollectionFreeFormLinksView.tsx | 18 ++--- .../collectionFreeForm/CollectionFreeFormView.tsx | 4 +- .../collections/collectionFreeForm/MarqueeView.tsx | 2 +- .../views/nodes/CollectionFreeFormDocumentView.tsx | 12 ++-- src/client/views/nodes/DocumentView.tsx | 5 +- src/client/views/nodes/FieldView.tsx | 5 +- src/client/views/nodes/ImageBox.tsx | 2 +- src/client/views/nodes/KeyValueBox.tsx | 5 +- src/client/views/nodes/PDFBox.tsx | 36 +++++----- src/client/views/nodes/VideoBox.tsx | 4 +- src/debug/Viewer.tsx | 7 +- src/fields/Document.ts | 14 ++-- src/fields/WebField.ts | 2 +- src/mobile/ImageUpload.tsx | 5 +- .../authentication/controllers/WorkspacesMenu.tsx | 2 +- .../authentication/controllers/user_controller.ts | 12 ++-- src/server/database.ts | 2 +- src/server/index.ts | 8 +-- test/test.ts | 2 +- tslint.json | 56 +++++++++++++++ webpack.config.js | 83 ++++++++++++---------- 43 files changed, 292 insertions(+), 259 deletions(-) create mode 100644 tslint.json (limited to 'src/client/northstar') diff --git a/package.json b/package.json index 27b3eead1..4fc253834 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,8 @@ "scss-loader": "0.0.1", "style-loader": "^0.23.1", "ts-node": "^7.0.1", + "tslint": "^5.15.0", + "tslint-loader": "^3.5.4", "typescript": "^3.3.3333", "webpack": "^4.29.6", "webpack-cli": "^3.2.3", diff --git a/src/Utils.ts b/src/Utils.ts index 3eb192eb8..8bd7f2f5c 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -18,7 +18,7 @@ export class Utils { return { scale: 1, translateX: 1, translateY: 1 } } const rect = ele.getBoundingClientRect(); - const scale = ele.offsetWidth == 0 && rect.width == 0 ? 1 : rect.width / ele.offsetWidth; + const scale = ele.offsetWidth === 0 && rect.width === 0 ? 1 : rect.width / ele.offsetWidth; const translateX = rect.left; const translateY = rect.top; diff --git a/src/client/Server.ts b/src/client/Server.ts index c301b04d3..e3f4448cb 100644 --- a/src/client/Server.ts +++ b/src/client/Server.ts @@ -21,11 +21,11 @@ export class Server { let fn = (cb: (field: Opt) => void) => { let cached = this.ClientFieldsCached.get(fieldid); - if (!cached) { + if (cached === undefined) { this.ClientFieldsCached.set(fieldid, FieldWaiting); SocketStub.SEND_FIELD_REQUEST(fieldid, action((field: Field | undefined) => { let cached = this.ClientFieldsCached.get(fieldid); - if (cached != FieldWaiting) + if (cached !== FieldWaiting) cb(cached); else { if (field) { @@ -36,23 +36,22 @@ export class Server { cb(field) } })); - } else if (cached != FieldWaiting) { + } else if (cached !== FieldWaiting) { setTimeout(() => cb(cached as Field), 0); } else { - reaction(() => { - return this.ClientFieldsCached.get(fieldid); - }, (field, reaction) => { - if (field !== FieldWaiting) { - reaction.dispose() - cb(field) - } - }) + reaction(() => + this.ClientFieldsCached.get(fieldid), (field, reaction) => { + if (field !== FieldWaiting) { + reaction.dispose() + cb(field) + } + }) } } if (callback) { fn(callback); } else { - return new Promise(res => fn(res)); + return new Promise(fn); } } @@ -92,24 +91,23 @@ export class Server { } } } - reaction(() => { - return waitingFieldIds.map(id => this.ClientFieldsCached.get(id)); - }, (cachedFields, reaction) => { - if (!cachedFields.some(field => !field || field === FieldWaiting)) { - reaction.dispose(); - for (let field of cachedFields) { - let realField = field as Field; - existingFields[realField.Id] = realField; + reaction(() => + waitingFieldIds.map(id => this.ClientFieldsCached.get(id)), (cachedFields, reaction) => { + if (!cachedFields.some(field => !field)) { + reaction.dispose(); + for (let field of cachedFields) { + let realField = field as Field; + existingFields[realField.Id] = realField; + } + cb({ ...fields, ...existingFields }) } - cb({ ...fields, ...existingFields }) - } - }, { fireImmediately: true }) + }, { fireImmediately: true }) })); }; if (callback) { fn(callback); } else { - return new Promise(res => fn(res)); + return new Promise(fn); } } @@ -153,19 +151,19 @@ export class Server { @action private static cacheField(clientField: Field) { var cached = this.ClientFieldsCached.get(clientField.Id); - if (!cached || cached == FieldWaiting) { + if (!cached || cached === FieldWaiting) { this.ClientFieldsCached.set(clientField.Id, clientField); } else { // probably should overwrite the values within any field that was already here... } - return this.ClientFieldsCached.get(clientField.Id) as Field; + return this.ClientFieldsCached.get(clientField.Id); } @action static updateField(field: { _id: string, data: any, type: Types }) { if (Server.ClientFieldsCached.has(field._id)) { var f = Server.ClientFieldsCached.get(field._id); - if (f && f != FieldWaiting) { + if (f && f !== FieldWaiting) { // console.log("Applying : " + field._id); f.UpdateFromServer(field.data); f.init(() => { }); diff --git a/src/client/SocketStub.ts b/src/client/SocketStub.ts index 5045037c5..c3cd8bee6 100644 --- a/src/client/SocketStub.ts +++ b/src/client/SocketStub.ts @@ -55,7 +55,7 @@ export class SocketStub { if (callback) { fn(callback); } else { - return new Promise(res => fn(res)) + return new Promise(fn) } } diff --git a/src/client/northstar/manager/Gateway.ts b/src/client/northstar/manager/Gateway.ts index 5ae5e4f47..3e72a50ae 100644 --- a/src/client/northstar/manager/Gateway.ts +++ b/src/client/northstar/manager/Gateway.ts @@ -246,18 +246,18 @@ export class Settings { else { this.ServerUrl = environment["SERVER_URL"] ? environment["SERVER_URL"] : document.URL; }*/ - this.ServerUrl = environment["SERVER_URL"] ? environment["SERVER_URL"] : document.URL; - this.ServerApiPath = environment["SERVER_API_PATH"]; - this.SampleSize = environment["SAMPLE_SIZE"]; - this.XBins = environment["X_BINS"]; - this.YBins = environment["Y_BINS"]; - this.SplashTimeInMS = environment["SPLASH_TIME_IN_MS"]; - this.ShowFpsCounter = environment["SHOW_FPS_COUNTER"]; - this.ShowShutdownButton = environment["SHOW_SHUTDOWN_BUTTON"]; - this.IsMenuFixed = environment["IS_MENU_FIXED"]; - this.IsDarpa = environment["IS_DARPA"]; - this.IsIGT = environment["IS_IGT"]; - this.DegreeOfParallelism = environment["DEGREE_OF_PARALLISM"]; + this.ServerUrl = environment.SERVER_URL ? environment.SERVER_URL : document.URL; + this.ServerApiPath = environment.SERVER_API_PATH; + this.SampleSize = environment.SAMPLE_SIZE; + this.XBins = environment.X_BINS; + this.YBins = environment.Y_BINS; + this.SplashTimeInMS = environment.SPLASH_TIME_IN_MS; + this.ShowFpsCounter = environment.SHOW_FPS_COUNTER; + this.ShowShutdownButton = environment.SHOW_SHUTDOWN_BUTTON; + this.IsMenuFixed = environment.IS_MENU_FIXED; + this.IsDarpa = environment.IS_DARPA; + this.IsIGT = environment.IS_IGT; + this.DegreeOfParallelism = environment.DEGREE_OF_PARALLISM; } public static get Instance(): Settings { diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index bf59fbb43..7cb368f47 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -29,7 +29,7 @@ export class DocumentManager { public getAllDocumentViews(collection: Document) { return this.DocumentViews.filter(dv => - dv.props.ContainingCollectionView && dv.props.ContainingCollectionView.props.Document == collection); + dv.props.ContainingCollectionView && dv.props.ContainingCollectionView.props.Document === collection); } public getDocumentView(toFind: Document): DocumentView | null { @@ -47,7 +47,7 @@ export class DocumentManager { return; } let docSrc = doc.GetT(KeyStore.Prototype, Document); - if (docSrc && docSrc != FieldWaiting && Object.is(docSrc, toFind)) { + if (docSrc && docSrc !== FieldWaiting && Object.is(docSrc, toFind)) { toReturn = view; } }) @@ -67,7 +67,7 @@ export class DocumentManager { toReturn.push(view); } else { let docSrc = doc.GetT(KeyStore.Prototype, Document); - if (docSrc && docSrc != FieldWaiting && Object.is(docSrc, toFind)) { + if (docSrc && docSrc !== FieldWaiting && Object.is(docSrc, toFind)) { toReturn.push(view); } } @@ -80,11 +80,11 @@ export class DocumentManager { public get LinkedDocumentViews() { return DocumentManager.Instance.DocumentViews.reduce((pairs, dv) => { let linksList = dv.props.Document.GetT(KeyStore.LinkedToDocs, ListField); - if (linksList && linksList != FieldWaiting && linksList.Data.length) { + if (linksList && linksList !== FieldWaiting && linksList.Data.length) { pairs.push(...linksList.Data.reduce((pairs, link) => { if (link instanceof Document) { let linkToDoc = link.GetT(KeyStore.LinkedToDocs, Document); - if (linkToDoc && linkToDoc != FieldWaiting) { + if (linkToDoc && linkToDoc !== FieldWaiting) { DocumentManager.Instance.getDocumentViews(linkToDoc).map(docView1 => { pairs.push({ a: dv, b: docView1, l: link }) }) diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 96c965c23..ff778302b 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -6,6 +6,7 @@ import { ImageField } from "../../fields/ImageField"; import { KeyStore } from "../../fields/KeyStore"; import { CollectionView } from "../views/collections/CollectionView"; import { DocumentView } from "../views/nodes/DocumentView"; +import { emptyFunction } from "../../Utils"; export function setupDrag(_reference: React.RefObject, docFunc: () => Document, removeFunc: (containingCollection: CollectionView) => void = () => { }) { let onRowMove = action((e: PointerEvent): void => { @@ -24,7 +25,7 @@ export function setupDrag(_reference: React.RefObject, docFunc: }); let onItemDown = (e: React.PointerEvent) => { // if (this.props.isSelected() || this.props.isTopMost) { - if (e.button == 0) { + if (e.button === 0) { e.stopPropagation(); if (e.shiftKey) { CollectionDockingView.Instance.StartOtherDrag([docFunc()], e); @@ -88,7 +89,7 @@ export namespace DragManager { if ("canDrop" in element.dataset) { throw new Error("Element is already droppable, can't make it droppable again"); } - element.dataset["canDrop"] = "true"; + element.dataset.canDrop = "true"; const handler = (e: Event) => { const ce = e as CustomEvent; options.handlers.drop(e, ce.detail); @@ -96,7 +97,7 @@ export namespace DragManager { element.addEventListener("dashOnDrop", handler); return () => { element.removeEventListener("dashOnDrop", handler); - delete element.dataset["canDrop"] + delete element.dataset.canDrop }; } @@ -167,11 +168,11 @@ export namespace DragManager { let thumbnail = docs[0].GetT(KeyStore.Thumbnail, ImageField); if (pdfBox && pdfBox.childElementCount && thumbnail) { let img = new Image(); - img!.src = thumbnail.toString(); - img!.style.position = "absolute"; - img!.style.width = `${rect.width / scaleX}px`; - img!.style.height = `${rect.height / scaleY}px`; - pdfBox.replaceChild(img!, pdfBox.children[0]) + img.src = thumbnail.toString(); + img.style.position = "absolute"; + img.style.width = `${rect.width / scaleX}px`; + img.style.height = `${rect.height / scaleY}px`; + pdfBox.replaceChild(img, pdfBox.children[0]) } } @@ -224,9 +225,9 @@ export namespace DragManager { }); const target = document.elementFromPoint(e.x, e.y); removed.map(r => { - let dragEle: HTMLElement = r[0]!; - let parent: HTMLElement | null = r[1]; - if (parent) + let dragEle = r[0]; + let parent = r[1]; + if (parent && dragEle) parent.appendChild(dragEle); }); if (target) { diff --git a/src/client/util/Scripting.ts b/src/client/util/Scripting.ts index 4e97b9401..8aef44a3a 100644 --- a/src/client/util/Scripting.ts +++ b/src/client/util/Scripting.ts @@ -26,7 +26,7 @@ export interface ExecutableScript { } function Compile(script: string | undefined, diagnostics: Opt, scope: { [name: string]: any }): ExecutableScript { - const compiled = !(diagnostics && diagnostics.some(diag => diag.category == ts.DiagnosticCategory.Error)); + const compiled = !(diagnostics && diagnostics.some(diag => diag.category === ts.DiagnosticCategory.Error)); let func: () => Opt; if (compiled && script) { @@ -40,7 +40,7 @@ function Compile(script: string | undefined, diagnostics: Opt, scope: { [ paramNames.push(prop); params.push(scope[prop]); } - let thisParam = scope["this"]; + let thisParam = scope.this; let compiledFunction = new Function(...paramNames, script); func = function (): Opt { return compiledFunction.apply(thisParam, params) @@ -49,10 +49,8 @@ function Compile(script: string | undefined, diagnostics: Opt, scope: { [ func = () => undefined; } - return Object.assign(func, - { - compiled - }); + Object.assign(func, { compiled }); + return func as ExecutableScript; } interface File { @@ -125,9 +123,9 @@ export function CompileScript(script: string, scope?: { [name: string]: any }, a } export function ToField(data: any): Opt { - if (typeof data == "string") { + if (typeof data === "string") { return new TextField(data); - } else if (typeof data == "number") { + } else if (typeof data === "number") { return new NumberField(data); } return undefined; diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts index 05810b61c..494420f0b 100644 --- a/src/client/util/SelectionManager.ts +++ b/src/client/util/SelectionManager.ts @@ -40,9 +40,8 @@ export namespace SelectionManager { export function DeselectAll(except?: Document): void { let found: DocumentView | undefined = undefined; if (except) { - for (let i = 0; i < manager.SelectedDocuments.length; i++) { - let view = manager.SelectedDocuments[i]; - if (view.props.Document == except) + for (const view of manager.SelectedDocuments) { + if (view.props.Document === except) found = view; } } diff --git a/src/client/util/Transform.ts b/src/client/util/Transform.ts index 889134e3e..8608264a1 100644 --- a/src/client/util/Transform.ts +++ b/src/client/util/Transform.ts @@ -62,33 +62,26 @@ export class Transform { return this; } - translated = (x: number, y: number): Transform => { - return this.copy().translate(x, y); - } + translated = (x: number, y: number): Transform => + this.copy().translate(x, y) - preTranslated = (x: number, y: number): Transform => { - return this.copy().preTranslate(x, y); - } + preTranslated = (x: number, y: number): Transform => + this.copy().preTranslate(x, y) - scaled = (scale: number): Transform => { - return this.copy().scale(scale); - } + scaled = (scale: number): Transform => + this.copy().scale(scale) - scaledAbout = (scale: number, x: number, y: number): Transform => { - return this.copy().scaleAbout(scale, x, y); - } + scaledAbout = (scale: number, x: number, y: number): Transform => + this.copy().scaleAbout(scale, x, y) - preScaled = (scale: number): Transform => { - return this.copy().preScale(scale); - } + preScaled = (scale: number): Transform => + this.copy().preScale(scale) - transformed = (transform: Transform): Transform => { - return this.copy().transform(transform); - } + transformed = (transform: Transform): Transform => + this.copy().transform(transform) - preTransformed = (transform: Transform): Transform => { - return this.copy().preTransform(transform); - } + preTransformed = (transform: Transform): Transform => + this.copy().preTransform(transform) transformPoint = (x: number, y: number): [number, number] => { x *= this._scale; @@ -98,9 +91,8 @@ export class Transform { return [x, y]; } - transformDirection = (x: number, y: number): [number, number] => { - return [x * this._scale, y * this._scale]; - } + transformDirection = (x: number, y: number): [number, number] => + [x * this._scale, y * this._scale] transformBounds(x: number, y: number, width: number, height: number): { x: number, y: number, width: number, height: number } { [x, y] = this.transformPoint(x, y); @@ -108,12 +100,10 @@ export class Transform { return { x, y, width, height }; } - inverse = () => { - return new Transform(-this._translateX / this._scale, -this._translateY / this._scale, 1 / this._scale) - } + inverse = () => + new Transform(-this._translateX / this._scale, -this._translateY / this._scale, 1 / this._scale) - copy = () => { - return new Transform(this._translateX, this._translateY, this._scale); - } + copy = () => + new Transform(this._translateX, this._translateY, this._scale) } \ No newline at end of file diff --git a/src/client/util/TypedEvent.ts b/src/client/util/TypedEvent.ts index 0714a7f5c..c590d3734 100644 --- a/src/client/util/TypedEvent.ts +++ b/src/client/util/TypedEvent.ts @@ -36,7 +36,6 @@ export class TypedEvent { this.listenersOncer = []; } - pipe = (te: TypedEvent): Disposable => { - return this.on((e) => te.emit(e)); - } + pipe = (te: TypedEvent): Disposable => + this.on((e) => te.emit(e)) } \ No newline at end of file diff --git a/src/client/util/UndoManager.ts b/src/client/util/UndoManager.ts index 6d1b2f1b8..1e5028375 100644 --- a/src/client/util/UndoManager.ts +++ b/src/client/util/UndoManager.ts @@ -159,8 +159,8 @@ export namespace UndoManager { } undoing = true; - for (let i = 0; i < commands.length; i++) { - commands[i].redo(); + for (const command of commands) { + command.redo(); } undoing = false; diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index d0699e1ab..b0aa190e5 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -75,7 +75,7 @@ export class DocumentDecorations extends React.Component { this._dragging = true; document.removeEventListener("pointermove", this.onBackgroundMove); document.removeEventListener("pointerup", this.onBackgroundUp); - DragManager.StartDocumentDrag(SelectionManager.SelectedDocuments().map(docView => (docView as any)._mainCont!.current!), dragData, { + DragManager.StartDocumentDrag(SelectionManager.SelectedDocuments().map(docView => (docView as any)._mainCont.current), dragData, { handlers: { dragComplete: action(() => this._dragging = false), }, diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx index 29bf6add7..982aacdea 100644 --- a/src/client/views/EditableView.tsx +++ b/src/client/views/EditableView.tsx @@ -38,7 +38,7 @@ export class EditableView extends React.Component { @action onKeyDown = (e: React.KeyboardEvent) => { - if (e.key == "Enter") { + if (e.key === "Enter") { if (!e.ctrlKey) { if (this.props.SetValue(e.currentTarget.value)) { this.editing = false; @@ -47,7 +47,7 @@ export class EditableView extends React.Component { this.props.OnFillDown(e.currentTarget.value); this.editing = false; } - } else if (e.key == "Escape") { + } else if (e.key === "Escape") { this.editing = false; } } diff --git a/src/client/views/InkingCanvas.tsx b/src/client/views/InkingCanvas.tsx index cad4b74b1..a2956f1b6 100644 --- a/src/client/views/InkingCanvas.tsx +++ b/src/client/views/InkingCanvas.tsx @@ -56,7 +56,7 @@ export class InkingCanvas extends React.Component { @action onPointerDown = (e: React.PointerEvent): void => { - if (e.button != 0 || e.altKey || e.ctrlKey || InkingControl.Instance.selectedTool === InkTool.None) { + if (e.button !== 0 || e.altKey || e.ctrlKey || InkingControl.Instance.selectedTool === InkTool.None) { return; } document.addEventListener("pointermove", this.onPointerMove, true); @@ -64,7 +64,7 @@ export class InkingCanvas extends React.Component { e.stopPropagation(); e.preventDefault(); - if (InkingControl.Instance.selectedTool != InkTool.Eraser) { + if (InkingControl.Instance.selectedTool !== InkTool.Eraser) { // start the new line, saves a uuid to represent the field of the stroke this._currentStrokeId = Utils.GenerateGuid(); this.inkData.set(this._currentStrokeId, { @@ -94,7 +94,7 @@ export class InkingCanvas extends React.Component { onPointerMove = (e: PointerEvent): void => { e.stopPropagation() e.preventDefault(); - if (InkingControl.Instance.selectedTool != InkTool.Eraser) { + if (InkingControl.Instance.selectedTool !== InkTool.Eraser) { let data = this.inkData; // add points to new line as it is being drawn let strokeData = data.get(this._currentStrokeId); if (strokeData) { @@ -121,7 +121,7 @@ export class InkingCanvas extends React.Component { get drawnPaths() { let curPage = this.props.Document.GetNumber(KeyStore.CurPage, -1) let paths = Array.from(this.inkData).reduce((paths, [id, strokeData]) => { - if (strokeData.page == -1 || strokeData.page == curPage) + if (strokeData.page === -1 || strokeData.page === curPage) paths.push( { }, [] as JSX.Element[]); return [ - {paths.filter(path => path.props.tool == InkTool.Highlighter)} + {paths.filter(path => path.props.tool === InkTool.Highlighter)} , - {paths.filter(path => path.props.tool != InkTool.Highlighter)} + {paths.filter(path => path.props.tool !== InkTool.Highlighter)} ]; } render() { - let svgCanvasStyle = InkingControl.Instance.selectedTool != InkTool.None ? "canSelect" : "noSelect"; + let svgCanvasStyle = InkingControl.Instance.selectedTool !== InkTool.None ? "canSelect" : "noSelect"; return (
diff --git a/src/client/views/InkingControl.tsx b/src/client/views/InkingControl.tsx index c1519dff8..13f0a0acc 100644 --- a/src/client/views/InkingControl.tsx +++ b/src/client/views/InkingControl.tsx @@ -36,9 +36,9 @@ export class InkingControl extends React.Component { @action switchColor = (color: ColorResult): void => { this._selectedColor = color.hex; - if (SelectionManager.SelectedDocuments().length == 1) { + if (SelectionManager.SelectedDocuments().length === 1) { var sdoc = SelectionManager.SelectedDocuments()[0]; - if (sdoc.props.ContainingCollectionView && sdoc.props.ContainingCollectionView) { + if (sdoc.props.ContainingCollectionView) { sdoc.props.Document.SetDataOnPrototype(KeyStore.BackgroundColor, color.hex, TextField); } } diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index 615f8af7e..dbb79c0c6 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -29,9 +29,8 @@ export class InkingStroke extends React.Component { } } - parseData = (line: Array<{ x: number, y: number }>): string => { - return !line.length ? "" : "M " + line.map(p => (p.x + this.props.offsetX) + " " + (p.y + this.props.offsetY)).join(" L "); - } + parseData = (line: Array<{ x: number, y: number }>): string => + !line.length ? "" : "M " + line.map(p => (p.x + this.props.offsetX) + " " + (p.y + this.props.offsetY)).join(" L ") createStyle() { switch (this._strokeTool) { @@ -49,7 +48,7 @@ export class InkingStroke extends React.Component { let pathStyle = this.createStyle(); let pathData = this.parseData(this.props.line); - let pointerEvents: any = InkingControl.Instance.selectedTool == InkTool.Eraser ? "all" : "none"; + let pointerEvents: any = InkingControl.Instance.selectedTool === InkTool.Eraser ? "all" : "none"; return ( diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index 8f67c006d..446c3d55f 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -204,9 +204,7 @@ export class Main extends React.Component { @observable workspacesShown: boolean = false; - areWorkspacesShown = () => { - return this.workspacesShown; - } + areWorkspacesShown = () => this.workspacesShown @action toggleWorkspaces = () => { this.workspacesShown = !this.workspacesShown; @@ -373,8 +371,7 @@ export class Main extends React.Component { } } -Documents.initProtos().then(() => { - return CurrentUserUtils.loadCurrentUser() -}).then(() => { - ReactDOM.render(
, document.getElementById('root')); -}); +Documents.initProtos().then(() => + CurrentUserUtils.loadCurrentUser()).then(() => { + ReactDOM.render(
, document.getElementById('root')); + }); diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx index 301467d99..9b68ee06c 100644 --- a/src/client/views/collections/CollectionBaseView.tsx +++ b/src/client/views/collections/CollectionBaseView.tsx @@ -2,7 +2,7 @@ import * as React from 'react'; import { FieldViewProps } from '../nodes/FieldView'; import { KeyStore } from '../../../fields/KeyStore'; import { NumberField } from '../../../fields/NumberField'; -import { FieldWaiting, Field } from '../../../fields/Field'; +import { FieldWaiting, Field, FieldValue } from '../../../fields/Field'; import { ContextMenu } from '../ContextMenu'; import { SelectionManager } from '../../util/SelectionManager'; import { Document } from '../../../fields/Document'; @@ -72,7 +72,7 @@ export class CollectionBaseView extends React.Component { if (this.createsCycle(annots[i], containerDocument)) return true; } - for (let containerProto: any = containerDocument; containerProto && containerProto != FieldWaiting; containerProto = containerProto.GetPrototype()) { + for (let containerProto: FieldValue = containerDocument; containerProto && containerProto != FieldWaiting; containerProto = containerProto.GetPrototype()) { if (containerProto.Id == documentToAdd.Id) return true; } diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index 78a813a99..ced46cc25 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -122,9 +122,7 @@ export class CollectionSchemaView extends CollectionViewBase { } return field || ""; }} - SetValue={(value: string) => { - return applyToDoc(props.Document, value); - }} + SetValue={(value: string) => applyToDoc(props.Document, value)} OnFillDown={(value: string) => { this.props.Document.GetTAsync>(this.props.fieldKey, ListField).then((val) => { if (val) { @@ -240,12 +238,8 @@ export class CollectionSchemaView extends CollectionViewBase { getContentScaling = (): number => this._contentScaling; getPanelWidth = (): number => this._panelWidth; getPanelHeight = (): number => this._panelHeight; - getTransform = (): Transform => { - return this.props.ScreenToLocalTransform().translate(- COLLECTION_BORDER_WIDTH - this.DIVIDER_WIDTH - this._dividerX, - COLLECTION_BORDER_WIDTH).scale(1 / this._contentScaling); - } - getPreviewTransform = (): Transform => { - return this.props.ScreenToLocalTransform().translate(- COLLECTION_BORDER_WIDTH - this.DIVIDER_WIDTH - this._dividerX - this._tableWidth, - COLLECTION_BORDER_WIDTH).scale(1 / this._contentScaling); - } + getTransform = (): Transform => this.props.ScreenToLocalTransform().translate(- COLLECTION_BORDER_WIDTH - this.DIVIDER_WIDTH - this._dividerX, - COLLECTION_BORDER_WIDTH).scale(1 / this._contentScaling) + getPreviewTransform = (): Transform => this.props.ScreenToLocalTransform().translate(- COLLECTION_BORDER_WIDTH - this.DIVIDER_WIDTH - this._dividerX - this._tableWidth, - COLLECTION_BORDER_WIDTH).scale(1 / this._contentScaling) focusDocument = (doc: Document) => { } @@ -332,9 +326,8 @@ export class CollectionSchemaView extends CollectionViewBase {
Show Preview
Displayed Columns
    - {Array.from(Object.keys(allKeys)).map(item => { - return () - })} + {Array.from(Object.keys(allKeys)).map(item => + ())}
diff --git a/src/client/views/collections/CollectionVideoView.tsx b/src/client/views/collections/CollectionVideoView.tsx index 7cb461b4d..3ab6db5ef 100644 --- a/src/client/views/collections/CollectionVideoView.tsx +++ b/src/client/views/collections/CollectionVideoView.tsx @@ -43,7 +43,7 @@ export class CollectionVideoView extends React.Component { @action mainCont = (ele: HTMLDivElement | null) => { if (ele) { - this._player = ele!.getElementsByTagName("video")[0]; + this._player = ele.getElementsByTagName("video")[0]; if (this.props.Document.GetNumber(KeyStore.CurPage, -1) >= 0) { this._currentTimecode = this.props.Document.GetNumber(KeyStore.CurPage, -1); } diff --git a/src/client/views/collections/CollectionViewBase.tsx b/src/client/views/collections/CollectionViewBase.tsx index 71a639137..51280275c 100644 --- a/src/client/views/collections/CollectionViewBase.tsx +++ b/src/client/views/collections/CollectionViewBase.tsx @@ -171,9 +171,8 @@ export class CollectionViewBase extends React.Component fetch(upload, { method: 'POST', body: formData - }).then((res: Response) => { - return res.json() - }).then(json => { + }).then((res: Response) => + res.json()).then(json => { json.map((file: any) => { let path = window.location.origin + file runInAction(() => { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx index eb20b3100..b682ab303 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx @@ -37,11 +37,11 @@ export class CollectionFreeFormLinksView extends React.Component) => field.Data.findIndex(brush => { let bdocs = brush.GetList(KeyStore.BrushingDocs, [] as Document[]); - return (bdocs.length == 0 || (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); - if (found != -1) + if (found !== -1) field.Data.splice(found, 1); }; if (Math.abs(x1 + x1w - x2) < 20 || Math.abs(x2 + x2w - x1) < 20) { @@ -50,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); @@ -63,10 +63,10 @@ export class CollectionFreeFormLinksView extends React.Component sv.props.ContainingCollectionView && sv.props.ContainingCollectionView.props.Document == this.props.Document); + return equalViews.filter(sv => sv.props.ContainingCollectionView && sv.props.ContainingCollectionView.props.Document === this.props.Document); } @computed @@ -78,14 +78,14 @@ export class CollectionFreeFormLinksView extends React.Component targetViews.map(tv => possiblePairs.push({ a: sv.props.Document, b: tv.props.Document }))); possiblePairs.map(possiblePair => { if (!drawnPairs.reduce((found, drawnPair) => { - let match = (possiblePair.a == drawnPair.a && possiblePair.b == drawnPair.b); + let match = (possiblePair.a === drawnPair.a && possiblePair.b === drawnPair.b); if (match) { - if (!drawnPair.l.reduce((found, link) => found || link.Id == connection.l.Id, false)) + if (!drawnPair.l.reduce((found, link) => found || link.Id === connection.l.Id, false)) drawnPair.l.push(connection.l); } return match || found; }, false)) { - drawnPairs.push({ a: possiblePair.a, b: possiblePair.b, l: [connection.l] as Document[] }); + drawnPairs.push({ a: possiblePair.a, b: possiblePair.b, l: [connection.l] }); } }) return drawnPairs diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index b04438ede..8c5d3f536 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -83,8 +83,8 @@ export class CollectionFreeFormView extends CollectionViewBase { drop = (e: Event, de: DragManager.DropEvent) => { if (super.drop(e, de)) { if (de.data instanceof DragManager.DocumentDragData) { - let screenX = de.x - (de.data.xOffset as number || 0); - let screenY = de.y - (de.data.yOffset as number || 0); + let screenX = de.x - (de.data.xOffset || 0); + let screenY = de.y - (de.data.yOffset || 0); const [x, y] = this.getTransform().transformPoint(screenX, screenY); let dragDoc = de.data.draggedDocuments[0]; let dragX = dragDoc.GetNumber(KeyStore.X, 0); diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index e2239c8be..b068d49d0 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -146,7 +146,7 @@ export class MarqueeView extends React.Component if (InkingCanvas.IntersectStrokeRect(value, this.Bounds)) { idata.set(key, { - pathData: value.pathData.map(val => { return { x: val.x + centerShiftX, y: val.y + centerShiftY } }), + pathData: value.pathData.map(val => ({ x: val.x + centerShiftX, y: val.y + centerShiftY })), color: value.color, width: value.width, tool: value.tool, diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index d52b662bd..e6475ee2a 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -52,14 +52,12 @@ export class CollectionFreeFormDocumentView extends React.Component { - return this.nativeWidth > 0 ? this.width / this.nativeWidth : 1; - } + contentScaling = () => + this.nativeWidth > 0 ? this.width / this.nativeWidth : 1 - getTransform = (): Transform => { - return this.props.ScreenToLocalTransform(). - translate(-this.props.Document.GetNumber(KeyStore.X, 0), -this.props.Document.GetNumber(KeyStore.Y, 0)).scale(1 / this.contentScaling()); - } + getTransform = (): Transform => + this.props.ScreenToLocalTransform(). + translate(-this.props.Document.GetNumber(KeyStore.X, 0), -this.props.Document.GetNumber(KeyStore.Y, 0)).scale(1 / this.contentScaling()) @computed get docView() { diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 6c05f6924..34eb8919f 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -287,9 +287,8 @@ export class DocumentView extends React.Component { } - isSelected = () => { - return SelectionManager.IsSelected(this); - } + isSelected = () => + SelectionManager.IsSelected(this) select = (ctrlPressed: boolean) => { SelectionManager.SelectDoc(this, ctrlPressed) diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index 4c6062a2f..d6035a076 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -96,9 +96,8 @@ export class FieldView extends React.Component { } else if (field instanceof ListField) { return (
- {(field as ListField).Data.map(f => { - return f instanceof Document ? f.Title : f.GetValue().toString(); - }).join(", ")} + {(field as ListField).Data.map(f => + f instanceof Document ? f.Title : f.GetValue().toString()).join(", ")}
) } // bcz: this belongs here, but it doesn't render well so taking it out for now diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 9b9dfe645..c5f29f7b0 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -104,7 +104,7 @@ export class ImageBox extends React.Component { render() { let field = this.props.Document.Get(this.props.fieldKey); - let path = field == FieldWaiting ? "https://image.flaticon.com/icons/svg/66/66163.svg" : + let path = field === FieldWaiting ? "https://image.flaticon.com/icons/svg/66/66163.svg" : field instanceof ImageField ? field.Data.href : "http://www.cs.brown.edu/~bcz/face.gif"; let nativeWidth = this.props.Document.GetNumber(KeyStore.NativeWidth, 1); return ( diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx index a3478143d..9b067aeeb 100644 --- a/src/client/views/nodes/KeyValueBox.tsx +++ b/src/client/views/nodes/KeyValueBox.tsx @@ -103,14 +103,13 @@ export class KeyValueBox extends React.Component { this._valueInput = e.currentTarget.value; } - newKeyValue = () => { - return ( + newKeyValue = () => + ( ) - } render() { return (
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 3b5e3a570..66c9f477e 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -94,7 +94,7 @@ export class PDFBox extends React.Component { this._reactionDisposer = reaction( () => [this.curPage, this.thumbnailPage], () => { - if (this.curPage > 0 && this.thumbnailPage > 0 && this.curPage != this.thumbnailPage) { + if (this.curPage > 0 && this.thumbnailPage > 0 && this.curPage !== this.thumbnailPage) { this.saveThumbnail(); this._interactive = true; } @@ -165,16 +165,16 @@ export class PDFBox extends React.Component { let obj: Object = { parentDivs: [], spans: [] }; //@ts-ignore - if (range.commonAncestorContainer.className == 'react-pdf__Page__textContent') { //multiline highlighting case + if (range.commonAncestorContainer.className === 'react-pdf__Page__textContent') { //multiline highlighting case obj = this.highlightNodes(range.commonAncestorContainer.childNodes) } else { //single line highlighting case let parentDiv = range.commonAncestorContainer.parentElement if (parentDiv) { - if (parentDiv.className == 'react-pdf__Page__textContent') { //when highlight is overwritten + if (parentDiv.className === 'react-pdf__Page__textContent') { //when highlight is overwritten obj = this.highlightNodes(parentDiv.childNodes) } else { parentDiv.childNodes.forEach((child) => { - if (child.nodeName == 'SPAN') { + if (child.nodeName === 'SPAN') { //@ts-ignore obj.parentDivs.push(parentDiv) //@ts-ignore @@ -197,7 +197,7 @@ export class PDFBox extends React.Component { let temp = { parentDivs: [], spans: [] } nodes.forEach((div) => { div.childNodes.forEach((child) => { - if (child.nodeName == 'SPAN') { + if (child.nodeName === 'SPAN') { //@ts-ignore temp.parentDivs.push(div) //@ts-ignore @@ -221,7 +221,7 @@ export class PDFBox extends React.Component { let index: any; this._pageInfo.divs.forEach((obj: any) => { obj.spans.forEach((element: any) => { - if (element == span) { + if (element === span) { if (!index) { index = this._pageInfo.divs.indexOf(obj); } @@ -230,11 +230,11 @@ export class PDFBox extends React.Component { }) if (this._pageInfo.anno.length >= index + 1) { - if (this._currAnno.length == 0) { + if (this._currAnno.length === 0) { this._currAnno.push(this._pageInfo.anno[index]); } } else { - if (this._currAnno.length == 0) { //if there are no current annotation + if (this._currAnno.length === 0) { //if there are no current annotation let div = span.offsetParent; //@ts-ignore let divX = div.style.left @@ -315,7 +315,7 @@ export class PDFBox extends React.Component { * starts drawing the line when user presses down. */ onDraw = () => { - if (this._currTool != null) { + if (this._currTool !== null) { this._currTool.style.backgroundColor = "grey"; } @@ -340,13 +340,13 @@ export class PDFBox extends React.Component { * for changing color (for ink/pen) */ onColorChange = (e: React.PointerEvent) => { - if (e.currentTarget.innerHTML == "Red") { + if (e.currentTarget.innerHTML === "Red") { this._currColor = "red"; - } else if (e.currentTarget.innerHTML == "Blue") { + } else if (e.currentTarget.innerHTML === "Blue") { this._currColor = "blue"; - } else if (e.currentTarget.innerHTML == "Green") { + } else if (e.currentTarget.innerHTML === "Green") { this._currColor = "green"; - } else if (e.currentTarget.innerHTML == "Black") { + } else if (e.currentTarget.innerHTML === "Black") { this._currColor = "black"; } @@ -358,7 +358,7 @@ export class PDFBox extends React.Component { */ onHighlight = () => { this._drawToolOn = false; - if (this._currTool != null) { + if (this._currTool !== null) { this._currTool.style.backgroundColor = "grey"; } if (this._highlightTool.current) { @@ -394,7 +394,7 @@ export class PDFBox extends React.Component { onLoaded = (page: any) => { if (this._mainDiv.current) { this._mainDiv.current.childNodes.forEach((element) => { - if (element.nodeName == "DIV") { + if (element.nodeName === "DIV") { element.childNodes[0].childNodes.forEach((e) => { if (e instanceof HTMLCanvasElement) { @@ -410,7 +410,7 @@ export class PDFBox extends React.Component { // bcz: the number of pages should really be set when the document is imported. this.props.Document.SetNumber(KeyStore.NumPages, page._transport.numPages); - if (this._perPageInfo.length == 0) { //Makes sure it only runs once + if (this._perPageInfo.length === 0) { //Makes sure it only runs once this._perPageInfo = [...Array(page._transport.numPages)] } this._loaded = true; @@ -455,7 +455,7 @@ export class PDFBox extends React.Component { get pdfRenderer() { let proxy = this._loaded ? (null) : this.imageProxyRenderer; let pdfUrl = this.props.Document.GetT(this.props.fieldKey, PDFField); - if ((!this._interactive && proxy) || !pdfUrl || pdfUrl == FieldWaiting) { + if ((!this._interactive && proxy) || !pdfUrl || pdfUrl === FieldWaiting) { return proxy; } return [ @@ -470,7 +470,7 @@ export class PDFBox extends React.Component { get imageProxyRenderer() { let thumbField = this.props.Document.Get(KeyStore.Thumbnail); if (thumbField) { - let path = thumbField == FieldWaiting || this.thumbnailPage != this.curPage ? "https://image.flaticon.com/icons/svg/66/66163.svg" : + let path = thumbField === FieldWaiting || this.thumbnailPage !== this.curPage ? "https://image.flaticon.com/icons/svg/66/66163.svg" : thumbField instanceof ImageField ? thumbField.Data.href : "http://cs.brown.edu/people/bcz/prairie.jpg"; return ; } diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index 72495a964..b4590df34 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -50,8 +50,8 @@ export class VideoBox extends React.Component { @action setVideoRef = (vref: HTMLVideoElement | null) => { if (this.curPage >= 0 && vref) { - vref!.currentTime = this.curPage; - (vref! as any).AHackBecauseSomethingResetsTheVideoToZero = this.curPage; + vref.currentTime = this.curPage; + (vref as any).AHackBecauseSomethingResetsTheVideoToZero = this.curPage; } } diff --git a/src/debug/Viewer.tsx b/src/debug/Viewer.tsx index 7fdd77bf3..9f52d0ea6 100644 --- a/src/debug/Viewer.tsx +++ b/src/debug/Viewer.tsx @@ -87,7 +87,7 @@ class DocumentViewer extends React.Component<{ field: Document }> { return (
({key ? key.Name : kv[0]}): - +
) }) @@ -177,9 +177,8 @@ class Viewer extends React.Component { onChange={this.inputOnChange} onKeyDown={this.onKeyPress} />
- {this.ids.map(id => { - return - })} + {this.ids.map(id => + )}
) diff --git a/src/fields/Document.ts b/src/fields/Document.ts index 85ff6ddcb..45e4f93f6 100644 --- a/src/fields/Document.ts +++ b/src/fields/Document.ts @@ -30,9 +30,9 @@ export class Document extends Field { } } - public Width = () => { return this.GetNumber(KeyStore.Width, 0) } - public Height = () => { return this.GetNumber(KeyStore.Height, this.GetNumber(KeyStore.NativeWidth, 0) ? this.GetNumber(KeyStore.NativeHeight, 0) / this.GetNumber(KeyStore.NativeWidth, 0) * this.GetNumber(KeyStore.Width, 0) : 0) } - public Scale = () => { return this.GetNumber(KeyStore.Scale, 1) } + public Width = () => this.GetNumber(KeyStore.Width, 0) + public Height = () => this.GetNumber(KeyStore.Height, this.GetNumber(KeyStore.NativeWidth, 0) ? this.GetNumber(KeyStore.NativeHeight, 0) / this.GetNumber(KeyStore.NativeWidth, 0) * this.GetNumber(KeyStore.Width, 0) : 0) + public Scale = () => this.GetNumber(KeyStore.Scale, 1) @computed public get Title(): string { @@ -90,7 +90,7 @@ export class Document extends Field { } } else { let doc: FieldValue = this; - while (doc && doc != FieldWaiting && field != FieldWaiting) { + while (doc && doc !== FieldWaiting && field !== FieldWaiting) { let curField = doc.fields.get(key.Id); let curProxy = doc._proxies.get(key.Id); if (!curField || (curProxy && curField.field.Id !== curProxy)) { @@ -118,7 +118,7 @@ export class Document extends Field { break; } } - if (doc == FieldWaiting) + if (doc === FieldWaiting) field = FieldWaiting; } @@ -165,7 +165,7 @@ export class Document extends Field { if (callback) { fn(callback); } else { - return new Promise(res => fn(res)); + return new Promise(fn); } } @@ -356,7 +356,7 @@ export class Document extends Field { let fields: [string, string][] = [] this._proxies.forEach((field, key) => { if (field) { - fields.push([key, field as string]) + fields.push([key, field]) } }); diff --git a/src/fields/WebField.ts b/src/fields/WebField.ts index 6c4de5000..0cbcc6d33 100644 --- a/src/fields/WebField.ts +++ b/src/fields/WebField.ts @@ -4,7 +4,7 @@ import { Types } from "../server/Message"; export class WebField extends BasicField { constructor(data: URL | undefined = undefined, id?: FieldId, save: boolean = true) { - super(data == undefined ? new URL("https://crossorigin.me/" + "https://cs.brown.edu/") : data, save, id); + super(data === undefined ? new URL("https://crossorigin.me/" + "https://cs.brown.edu/") : data, save, id); } toString(): string { diff --git a/src/mobile/ImageUpload.tsx b/src/mobile/ImageUpload.tsx index ae48dd2c6..c4d346876 100644 --- a/src/mobile/ImageUpload.tsx +++ b/src/mobile/ImageUpload.tsx @@ -33,9 +33,8 @@ const onFileLoad = (file: any) => { fetch(upload, { method: 'POST', body: formData - }).then((res: Response) => { - return res.json() - }).then(json => { + }).then((res: Response) => + res.json()).then(json => { json.map((file: any) => { let path = window.location.origin + file var doc: Document = Documents.ImageDocument(path, { nativeWidth: 200, width: 200 }) diff --git a/src/server/authentication/controllers/WorkspacesMenu.tsx b/src/server/authentication/controllers/WorkspacesMenu.tsx index 8e14cf98e..835432c8e 100644 --- a/src/server/authentication/controllers/WorkspacesMenu.tsx +++ b/src/server/authentication/controllers/WorkspacesMenu.tsx @@ -73,7 +73,7 @@ export class WorkspacesMenu extends React.Component { {i + 1} - { return s.Title }} + GetValue={() => s.Title} SetValue={(title: string): boolean => { s.SetText(KeyStore.Title, title); return true; diff --git a/src/server/authentication/controllers/user_controller.ts b/src/server/authentication/controllers/user_controller.ts index e365b8dce..2bbb334b5 100644 --- a/src/server/authentication/controllers/user_controller.ts +++ b/src/server/authentication/controllers/user_controller.ts @@ -4,7 +4,7 @@ import * as passport from "passport"; import { IVerifyOptions } from "passport-local"; import "../config/passport"; import * as request from "express-validator"; -const flash = require("express-flash"); +import flash = require("express-flash"); import * as session from "express-session"; import * as pug from 'pug'; import * as async from 'async'; @@ -109,12 +109,12 @@ export let postLogin = (req: Request, res: Response, next: NextFunction) => { } passport.authenticate("local", (err: Error, user: DashUserModel, info: IVerifyOptions) => { - if (err) { return next(err); } + if (err) { next(err); return } if (!user) { return res.redirect(RouteStore.signup); } req.logIn(user, (err) => { - if (err) { return next(err); } + if (err) { next(err); return } res.redirect(RouteStore.home); }); })(req, res, next); @@ -158,7 +158,8 @@ export let postForgot = function (req: Request, res: Response, next: NextFunctio User.findOne({ email }, function (err, user: DashUserModel) { if (!user) { // NO ACCOUNT WITH SUBMITTED EMAIL - return res.redirect(RouteStore.forgot); + res.redirect(RouteStore.forgot); + return } user.passwordResetToken = token; user.passwordResetExpires = new Date(Date.now() + 3600000); // 1 HOUR @@ -228,7 +229,8 @@ export let postReset = function (req: Request, res: Response) { user.save(function (err) { if (err) { - return res.redirect(RouteStore.login); + res.redirect(RouteStore.login); + return; } req.logIn(user, function (err) { if (err) { diff --git a/src/server/database.ts b/src/server/database.ts index a42d29aac..87a0b3c70 100644 --- a/src/server/database.ts +++ b/src/server/database.ts @@ -27,7 +27,7 @@ export class Database { console.log(err.errmsg); } if (res) { - console.log(JSON.stringify(res.result)); + // console.log(JSON.stringify(res.result)); } callback() }); diff --git a/src/server/index.ts b/src/server/index.ts index 17d7432e0..0c61f6885 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -264,11 +264,9 @@ function deleteFields() { } function deleteAll() { - return Database.Instance.deleteAll().then(() => { - return Database.Instance.deleteAll('sessions') - }).then(() => { - return Database.Instance.deleteAll('users') - }); + return Database.Instance.deleteAll().then(() => + Database.Instance.deleteAll('sessions')).then(() => + Database.Instance.deleteAll('users')); } function barReceived(guid: String) { diff --git a/test/test.ts b/test/test.ts index 0fa1ea15b..db24cae5f 100644 --- a/test/test.ts +++ b/test/test.ts @@ -152,7 +152,7 @@ describe("Reference", () => { let ran = false; reaction(() => { let field = doc2.GetT(key, NumberField); - if (field && field != FieldWaiting) { + if (field && field !== FieldWaiting) { return field.Data; } return undefined; diff --git a/tslint.json b/tslint.json new file mode 100644 index 000000000..54876916e --- /dev/null +++ b/tslint.json @@ -0,0 +1,56 @@ +{ + "rules": { + // "no-non-null-assertion": true, + "no-return-await": true, + "no-string-literal": true, + // "no-var-keyword": true, + // "no-var-requires": true, + "prefer-object-spread": true, + "prefer-for-of": true, + "no-unnecessary-type-assertion": true, + // "no-void-expression": [ + // true, + // "ignore-arrow-function-shorthand" + // ], + "triple-equals": true, + // "prefer-const": true, + "no-unnecessary-callback-wrapper": true, + // "align": [ + // true, + // "parameters", + // "arguments", + // "statements", + // "members", + // "elements" + // ], + "class-name": true, + "arrow-return-shorthand": true, + // "object-literal-shorthand": true, + // "object-literal-sort-keys": true, + // "semicolon": [ + // true, + // "always" + // ], + // "curly": [ + // true, + // "ignore-same-line" + // ], + // "quotemark": [ + // true, + // "double", + // "jsx-double", + // "avoid-template", + // "avoid-escape" + // ], + "no-tautology-expression": true, + "unnecessary-constructor": true + // "trailing-comma": [ + // true, + // { + // "multiline": "always", + // "singleline": "never" + // } + // ], + // "ordered-imports": true + } +} \ No newline at end of file diff --git a/webpack.config.js b/webpack.config.js index 5ba9dd4b5..50079255f 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -28,44 +28,53 @@ module.exports = { extensions: ['.js', '.ts', '.tsx'] }, module: { - rules: [{ - test: [/\.tsx?$/, /\.ts?$/,], - loader: "awesome-typescript-loader", - include: path.join(__dirname, 'src') - }, - { - test: /\.scss|css$/, - use: [ - { - loader: "style-loader" - }, - { - loader: "css-loader" - }, - { - loader: "sass-loader" - } - ] - }, - { - test: /\.(jpg|png|pdf)$/, - use: [ - { - loader: 'file-loader' - } - ] - }, - { - test: /\.(png|jpg|gif)$/i, - use: [ - { - loader: 'url-loader', - options: { - limit: 8192 + rules: [ + { + test: [/\.tsx?$/, /\.ts?$/,], + enforce: 'pre', + use: [ + { + loader: "tslint-loader", } - } - ] - }] + ] + }, { + test: [/\.tsx?$/, /\.ts?$/,], + loader: "awesome-typescript-loader", + include: path.join(__dirname, 'src') + }, + { + test: /\.scss|css$/, + use: [ + { + loader: "style-loader" + }, + { + loader: "css-loader" + }, + { + loader: "sass-loader" + } + ] + }, + { + test: /\.(jpg|png|pdf)$/, + use: [ + { + loader: 'file-loader' + } + ] + }, + { + test: /\.(png|jpg|gif)$/i, + use: [ + { + loader: 'url-loader', + options: { + limit: 8192 + } + } + ] + }] }, plugins: [ new CopyWebpackPlugin([{ from: "deploy", to: path.join(__dirname, "build") }]), -- cgit v1.2.3-70-g09d2 From b78aff5115862cbfa5e704422cb738aa7fd73c64 Mon Sep 17 00:00:00 2001 From: bob Date: Thu, 4 Apr 2019 14:13:29 -0400 Subject: fixed a number of smaller issues related to linking --- src/client/northstar/dash-nodes/HistogramBox.scss | 5 + src/client/util/DragManager.ts | 533 +++++++------- src/client/util/SelectionManager.ts | 74 +- src/client/views/DocumentDecorations.scss | 61 +- src/client/views/DocumentDecorations.tsx | 81 ++- src/client/views/InkingCanvas.scss | 2 + src/client/views/Main.scss | 7 + .../views/collections/CollectionDockingView.scss | 2 +- .../views/collections/CollectionPDFView.scss | 2 + .../views/collections/CollectionVideoView.scss | 2 + .../views/collections/CollectionViewBase.tsx | 20 + .../CollectionFreeFormLinkView.tsx | 8 +- .../CollectionFreeFormLinksView.scss | 2 + .../collectionFreeForm/CollectionFreeFormView.scss | 6 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 13 +- .../collectionFreeForm/MarqueeView.scss | 2 + .../collectionFreeForm/PreviewCursor.scss | 4 + .../views/nodes/CollectionFreeFormDocumentView.tsx | 4 + src/client/views/nodes/DocumentView.scss | 2 + src/client/views/nodes/PDFBox.scss | 4 + src/client/views/nodes/WebBox.scss | 2 + src/fields/Document.ts | 773 +++++++++++---------- 22 files changed, 882 insertions(+), 727 deletions(-) (limited to 'src/client/northstar') diff --git a/src/client/northstar/dash-nodes/HistogramBox.scss b/src/client/northstar/dash-nodes/HistogramBox.scss index b11840a65..94da36e29 100644 --- a/src/client/northstar/dash-nodes/HistogramBox.scss +++ b/src/client/northstar/dash-nodes/HistogramBox.scss @@ -1,6 +1,8 @@ .histogrambox-container { padding: 0vw; position: absolute; + top: 0; + left:0; text-align: center; width: 100%; height: 100%; @@ -8,6 +10,7 @@ } .histogrambox-xaxislabel { position:absolute; + left:0; width:100%; text-align: center; bottom:0; @@ -19,11 +22,13 @@ position:absolute; height:100%; width: 25px; + left:0; bottom:0; background: lightgray; } .histogrambox-yaxislabel-text { position:absolute; + left:0; transform-origin: left; transform: rotate(-90deg); text-align: center; diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index c0f482e18..e8f8cce7c 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -8,304 +8,307 @@ import { CollectionView } from "../views/collections/CollectionView"; import { DocumentView } from "../views/nodes/DocumentView"; export function setupDrag( - _reference: React.RefObject, - docFunc: () => Document, - removeFunc: (containingCollection: CollectionView) => void = () => {} + _reference: React.RefObject, + docFunc: () => Document, + removeFunc: (containingCollection: CollectionView) => void = () => { } ) { - let onRowMove = action( - (e: PointerEvent): void => { - e.stopPropagation(); - e.preventDefault(); + let onRowMove = action( + (e: PointerEvent): void => { + e.stopPropagation(); + e.preventDefault(); - document.removeEventListener("pointermove", onRowMove); - document.removeEventListener("pointerup", onRowUp); - var dragData = new DragManager.DocumentDragData([docFunc()]); - dragData.removeDocument = removeFunc; - DragManager.StartDocumentDrag([_reference.current!], dragData); - } - ); - let onRowUp = action( - (e: PointerEvent): void => { - document.removeEventListener("pointermove", onRowMove); - document.removeEventListener("pointerup", onRowUp); - } - ); - let onItemDown = (e: React.PointerEvent) => { - // if (this.props.isSelected() || this.props.isTopMost) { - if (e.button == 0) { - e.stopPropagation(); - if (e.shiftKey) { - CollectionDockingView.Instance.StartOtherDrag([docFunc()], e); - } else { - document.addEventListener("pointermove", onRowMove); - document.addEventListener("pointerup", onRowUp); - } - } - //} - }; - return onItemDown; + document.removeEventListener("pointermove", onRowMove); + document.removeEventListener("pointerup", onRowUp); + var dragData = new DragManager.DocumentDragData([docFunc()]); + dragData.removeDocument = removeFunc; + DragManager.StartDocumentDrag([_reference.current!], dragData); + } + ); + let onRowUp = action( + (e: PointerEvent): void => { + document.removeEventListener("pointermove", onRowMove); + document.removeEventListener("pointerup", onRowUp); + } + ); + let onItemDown = (e: React.PointerEvent) => { + // if (this.props.isSelected() || this.props.isTopMost) { + if (e.button == 0) { + e.stopPropagation(); + if (e.shiftKey) { + CollectionDockingView.Instance.StartOtherDrag([docFunc()], e); + } else { + document.addEventListener("pointermove", onRowMove); + document.addEventListener("pointerup", onRowUp); + } + } + //} + }; + return onItemDown; } export namespace DragManager { - export function Root() { - const root = document.getElementById("root"); - if (!root) { - throw new Error("No root element found"); + export function Root() { + const root = document.getElementById("root"); + if (!root) { + throw new Error("No root element found"); + } + return root; } - return root; - } - let dragDiv: HTMLDivElement; + let dragDiv: HTMLDivElement; - export enum DragButtons { - Left = 1, - Right = 2, - Both = Left | Right - } + export enum DragButtons { + Left = 1, + Right = 2, + Both = Left | Right + } - interface DragOptions { - handlers: DragHandlers; + interface DragOptions { + handlers: DragHandlers; - hideSource: boolean | (() => boolean); - } + hideSource: boolean | (() => boolean); + } - export interface DragDropDisposer { - (): void; - } + export interface DragDropDisposer { + (): void; + } - export class DragCompleteEvent {} + export class DragCompleteEvent { } - export interface DragHandlers { - dragComplete: (e: DragCompleteEvent) => void; - } + export interface DragHandlers { + dragComplete: (e: DragCompleteEvent) => void; + } - export interface DropOptions { - handlers: DropHandlers; - } - export class DropEvent { - constructor( - readonly x: number, - readonly y: number, - readonly data: { [id: string]: any } - ) {} - } + export interface DropOptions { + handlers: DropHandlers; + } + export class DropEvent { + constructor( + readonly x: number, + readonly y: number, + readonly data: { [id: string]: any } + ) { } + } - export interface DropHandlers { - drop: (e: Event, de: DropEvent) => void; - } + export interface DropHandlers { + drop: (e: Event, de: DropEvent) => void; + } - export function MakeDropTarget( - element: HTMLElement, - options: DropOptions - ): DragDropDisposer { - if ("canDrop" in element.dataset) { - throw new Error( - "Element is already droppable, can't make it droppable again" - ); + export function MakeDropTarget( + element: HTMLElement, + options: DropOptions + ): DragDropDisposer { + if ("canDrop" in element.dataset) { + throw new Error( + "Element is already droppable, can't make it droppable again" + ); + } + element.dataset["canDrop"] = "true"; + const handler = (e: Event) => { + const ce = e as CustomEvent; + options.handlers.drop(e, ce.detail); + }; + element.addEventListener("dashOnDrop", handler); + return () => { + element.removeEventListener("dashOnDrop", handler); + delete element.dataset["canDrop"]; + }; } - element.dataset["canDrop"] = "true"; - const handler = (e: Event) => { - const ce = e as CustomEvent; - options.handlers.drop(e, ce.detail); - }; - element.addEventListener("dashOnDrop", handler); - return () => { - element.removeEventListener("dashOnDrop", handler); - delete element.dataset["canDrop"]; - }; - } - export class DocumentDragData { - constructor(dragDoc: Document[]) { - this.draggedDocuments = dragDoc; - this.droppedDocuments = dragDoc; + export class DocumentDragData { + constructor(dragDoc: Document[]) { + this.draggedDocuments = dragDoc; + this.droppedDocuments = dragDoc; + } + draggedDocuments: Document[]; + droppedDocuments: Document[]; + xOffset?: number; + yOffset?: number; + aliasOnDrop?: boolean; + removeDocument?: (collectionDrop: CollectionView) => void; + [id: string]: any; } - draggedDocuments: Document[]; - droppedDocuments: Document[]; - xOffset?: number; - yOffset?: number; - aliasOnDrop?: boolean; - removeDocument?: (collectionDrop: CollectionView) => void; - [id: string]: any; - } - export function StartDocumentDrag( - eles: HTMLElement[], - dragData: DocumentDragData, - options?: DragOptions - ) { - StartDrag( - eles, - dragData, - options, - (dropData: { [id: string]: any }) => - (dropData.droppedDocuments = dragData.aliasOnDrop - ? dragData.draggedDocuments.map(d => d.CreateAlias()) - : dragData.draggedDocuments) - ); - } + export function StartDocumentDrag( + eles: HTMLElement[], + dragData: DocumentDragData, + options?: DragOptions + ) { + StartDrag( + eles, + dragData, + options, + (dropData: { [id: string]: any }) => + (dropData.droppedDocuments = dragData.aliasOnDrop + ? dragData.draggedDocuments.map(d => d.CreateAlias()) + : dragData.draggedDocuments) + ); + } - export class LinkDragData { - constructor(linkSourceDoc: DocumentView) { - this.linkSourceDocumentView = linkSourceDoc; + export class LinkDragData { + constructor(linkSourceDoc: DocumentView) { + this.linkSourceDocumentView = linkSourceDoc; + } + droppedDocuments: Document[] = []; + linkSourceDocumentView: DocumentView; + [id: string]: any; } - linkSourceDocumentView: DocumentView; - [id: string]: any; - } - export function StartLinkDrag( - ele: HTMLElement, - dragData: LinkDragData, - options?: DragOptions - ) { - StartDrag([ele], dragData, options); - } - function StartDrag( - eles: HTMLElement[], - dragData: { [id: string]: any }, - options?: DragOptions, - finishDrag?: (dropData: { [id: string]: any }) => void - ) { - if (!dragDiv) { - dragDiv = document.createElement("div"); - dragDiv.className = "dragManager-dragDiv"; - DragManager.Root().appendChild(dragDiv); + export function StartLinkDrag( + ele: HTMLElement, + dragData: LinkDragData, + options?: DragOptions + ) { + StartDrag([ele], dragData, options); } + function StartDrag( + eles: HTMLElement[], + dragData: { [id: string]: any }, + options?: DragOptions, + finishDrag?: (dropData: { [id: string]: any }) => void + ) { + if (!dragDiv) { + dragDiv = document.createElement("div"); + dragDiv.className = "dragManager-dragDiv"; + DragManager.Root().appendChild(dragDiv); + } - let scaleXs: number[] = []; - let scaleYs: number[] = []; - let xs: number[] = []; - let ys: number[] = []; + let scaleXs: number[] = []; + let scaleYs: number[] = []; + let xs: number[] = []; + let ys: number[] = []; - const docs: Document[] = - dragData instanceof DocumentDragData ? dragData.draggedDocuments : []; - let dragElements = eles.map(ele => { - const w = ele.offsetWidth, - h = ele.offsetHeight; - const rect = ele.getBoundingClientRect(); - const scaleX = rect.width / w, - scaleY = rect.height / h; - let x = rect.left, - y = rect.top; - xs.push(x); - ys.push(y); - scaleXs.push(scaleX); - scaleYs.push(scaleY); - let dragElement = ele.cloneNode(true) as HTMLElement; - dragElement.style.opacity = "0.7"; - dragElement.style.position = "absolute"; - dragElement.style.bottom = ""; - dragElement.style.left = ""; - dragElement.style.transformOrigin = "0 0"; - dragElement.style.zIndex = "1000"; - dragElement.style.transform = `translate(${x}px, ${y}px) scale(${scaleX}, ${scaleY})`; - dragElement.style.width = `${rect.width / scaleX}px`; - dragElement.style.height = `${rect.height / scaleY}px`; + const docs: Document[] = + dragData instanceof DocumentDragData ? dragData.draggedDocuments : []; + let dragElements = eles.map(ele => { + const w = ele.offsetWidth, + h = ele.offsetHeight; + const rect = ele.getBoundingClientRect(); + const scaleX = rect.width / w, + scaleY = rect.height / h; + let x = rect.left, + y = rect.top; + xs.push(x); + ys.push(y); + scaleXs.push(scaleX); + scaleYs.push(scaleY); + let dragElement = ele.cloneNode(true) as HTMLElement; + dragElement.style.opacity = "0.7"; + dragElement.style.position = "absolute"; + dragElement.style.margin = "0"; + dragElement.style.top = "0"; + dragElement.style.bottom = ""; + dragElement.style.left = "0"; + dragElement.style.transformOrigin = "0 0"; + dragElement.style.zIndex = "1000"; + dragElement.style.transform = `translate(${x}px, ${y}px) scale(${scaleX}, ${scaleY})`; + dragElement.style.width = `${rect.width / scaleX}px`; + dragElement.style.height = `${rect.height / scaleY}px`; - // bcz: PDFs don't show up if you clone them because they contain a canvas. - // however, PDF's have a thumbnail field that contains an image of their canvas. - // So we replace the pdf's canvas with the image thumbnail - if (docs.length) { - var pdfBox = dragElement.getElementsByClassName( - "pdfBox-cont" - )[0] as HTMLElement; - let thumbnail = docs[0].GetT(KeyStore.Thumbnail, ImageField); - if (pdfBox && pdfBox.childElementCount && thumbnail) { - let img = new Image(); - img!.src = thumbnail.toString(); - img!.style.position = "absolute"; - img!.style.width = `${rect.width / scaleX}px`; - img!.style.height = `${rect.height / scaleY}px`; - pdfBox.replaceChild(img!, pdfBox.children[0]); + // bcz: PDFs don't show up if you clone them because they contain a canvas. + // however, PDF's have a thumbnail field that contains an image of their canvas. + // So we replace the pdf's canvas with the image thumbnail + if (docs.length) { + var pdfBox = dragElement.getElementsByClassName( + "pdfBox-cont" + )[0] as HTMLElement; + let thumbnail = docs[0].GetT(KeyStore.Thumbnail, ImageField); + if (pdfBox && pdfBox.childElementCount && thumbnail) { + let img = new Image(); + img!.src = thumbnail.toString(); + img!.style.position = "absolute"; + img!.style.width = `${rect.width / scaleX}px`; + img!.style.height = `${rect.height / scaleY}px`; + pdfBox.replaceChild(img!, pdfBox.children[0]); + } + } + + dragDiv.appendChild(dragElement); + return dragElement; + }); + + let hideSource = false; + if (options) { + if (typeof options.hideSource === "boolean") { + hideSource = options.hideSource; + } else { + hideSource = options.hideSource(); + } } - } + eles.map(ele => (ele.hidden = hideSource)); - dragDiv.appendChild(dragElement); - return dragElement; - }); + const moveHandler = (e: PointerEvent) => { + e.stopPropagation(); + e.preventDefault(); + if (dragData instanceof DocumentDragData) + dragData.aliasOnDrop = e.ctrlKey || e.altKey; + if (e.shiftKey) { + abortDrag(); + CollectionDockingView.Instance.StartOtherDrag(docs, { + pageX: e.pageX, + pageY: e.pageY, + preventDefault: () => { }, + button: 0 + }); + } + dragElements.map( + (dragElement, i) => + (dragElement.style.transform = `translate(${(xs[i] += + e.movementX)}px, ${(ys[i] += e.movementY)}px) scale(${ + scaleXs[i] + }, ${scaleYs[i]})`) + ); + }; - let hideSource = false; - if (options) { - if (typeof options.hideSource === "boolean") { - hideSource = options.hideSource; - } else { - hideSource = options.hideSource(); - } + const abortDrag = () => { + document.removeEventListener("pointermove", moveHandler, true); + document.removeEventListener("pointerup", upHandler); + dragElements.map(dragElement => dragDiv.removeChild(dragElement)); + eles.map(ele => (ele.hidden = false)); + }; + const upHandler = (e: PointerEvent) => { + abortDrag(); + FinishDrag(eles, e, dragData, options, finishDrag); + }; + document.addEventListener("pointermove", moveHandler, true); + document.addEventListener("pointerup", upHandler); } - eles.map(ele => (ele.hidden = hideSource)); - const moveHandler = (e: PointerEvent) => { - e.stopPropagation(); - e.preventDefault(); - if (dragData instanceof DocumentDragData) - dragData.aliasOnDrop = e.ctrlKey || e.altKey; - if (e.shiftKey) { - abortDrag(); - CollectionDockingView.Instance.StartOtherDrag(docs, { - pageX: e.pageX, - pageY: e.pageY, - preventDefault: () => {}, - button: 0 + function FinishDrag( + dragEles: HTMLElement[], + e: PointerEvent, + dragData: { [index: string]: any }, + options?: DragOptions, + finishDrag?: (dragData: { [index: string]: any }) => void + ) { + let removed = dragEles.map(dragEle => { + let parent = dragEle.parentElement; + if (parent) parent.removeChild(dragEle); + return [dragEle, parent]; }); - } - dragElements.map( - (dragElement, i) => - (dragElement.style.transform = `translate(${(xs[i] += - e.movementX)}px, ${(ys[i] += e.movementY)}px) scale(${ - scaleXs[i] - }, ${scaleYs[i]})`) - ); - }; - - const abortDrag = () => { - document.removeEventListener("pointermove", moveHandler, true); - document.removeEventListener("pointerup", upHandler); - dragElements.map(dragElement => dragDiv.removeChild(dragElement)); - eles.map(ele => (ele.hidden = false)); - }; - const upHandler = (e: PointerEvent) => { - abortDrag(); - FinishDrag(eles, e, dragData, options, finishDrag); - }; - document.addEventListener("pointermove", moveHandler, true); - document.addEventListener("pointerup", upHandler); - } - - function FinishDrag( - dragEles: HTMLElement[], - e: PointerEvent, - dragData: { [index: string]: any }, - options?: DragOptions, - finishDrag?: (dragData: { [index: string]: any }) => void - ) { - let removed = dragEles.map(dragEle => { - let parent = dragEle.parentElement; - if (parent) parent.removeChild(dragEle); - return [dragEle, parent]; - }); - const target = document.elementFromPoint(e.x, e.y); - removed.map(r => { - let dragEle: HTMLElement = r[0]!; - let parent: HTMLElement | null = r[1]; - if (parent) parent.appendChild(dragEle); - }); - if (target) { - if (finishDrag) finishDrag(dragData); + const target = document.elementFromPoint(e.x, e.y); + removed.map(r => { + let dragEle: HTMLElement = r[0]!; + let parent: HTMLElement | null = r[1]; + if (parent) parent.appendChild(dragEle); + }); + if (target) { + if (finishDrag) finishDrag(dragData); - target.dispatchEvent( - new CustomEvent("dashOnDrop", { - bubbles: true, - detail: { - x: e.x, - y: e.y, - data: dragData - } - }) - ); + target.dispatchEvent( + new CustomEvent("dashOnDrop", { + bubbles: true, + detail: { + x: e.x, + y: e.y, + data: dragData + } + }) + ); - if (options) { - options.handlers.dragComplete({}); - } + if (options) { + options.handlers.dragComplete({}); + } + } + DocumentDecorations.Instance.Hidden = false; } - DocumentDecorations.Instance.Hidden = false; - } } diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts index 438659108..958c14491 100644 --- a/src/client/util/SelectionManager.ts +++ b/src/client/util/SelectionManager.ts @@ -3,48 +3,46 @@ import { DocumentView } from "../views/nodes/DocumentView"; import { Document } from "../../fields/Document"; export namespace SelectionManager { - class Manager { - @observable - SelectedDocuments: Array = []; - - @action - SelectDoc(doc: DocumentView, ctrlPressed: boolean): void { - // if doc is not in SelectedDocuments, add it - if (!ctrlPressed) { - manager.SelectedDocuments = []; - } - - if (manager.SelectedDocuments.indexOf(doc) === -1) { - manager.SelectedDocuments.push(doc); - } + class Manager { + @observable + SelectedDocuments: Array = []; + + @action + SelectDoc(doc: DocumentView, ctrlPressed: boolean): void { + // if doc is not in SelectedDocuments, add it + if (!ctrlPressed) { + manager.SelectedDocuments = []; + } + + if (manager.SelectedDocuments.indexOf(doc) === -1) { + manager.SelectedDocuments.push(doc); + } + } } - } - const manager = new Manager(); + const manager = new Manager(); - export function SelectDoc(doc: DocumentView, ctrlPressed: boolean): void { - if (!doc.isMinimized()) { - manager.SelectDoc(doc, ctrlPressed); + export function SelectDoc(doc: DocumentView, ctrlPressed: boolean): void { + manager.SelectDoc(doc, ctrlPressed); } - } - - export function IsSelected(doc: DocumentView): boolean { - return manager.SelectedDocuments.indexOf(doc) !== -1; - } - - export function DeselectAll(except?: Document): void { - let found: DocumentView | undefined = undefined; - if (except) { - for (let i = 0; i < manager.SelectedDocuments.length; i++) { - let view = manager.SelectedDocuments[i]; - if (view.props.Document == except) found = view; - } + + export function IsSelected(doc: DocumentView): boolean { + return manager.SelectedDocuments.indexOf(doc) !== -1; + } + + export function DeselectAll(except?: Document): void { + let found: DocumentView | undefined = undefined; + if (except) { + for (let i = 0; i < manager.SelectedDocuments.length; i++) { + let view = manager.SelectedDocuments[i]; + if (view.props.Document == except) found = view; + } + } + manager.SelectedDocuments.length = 0; + if (found) manager.SelectedDocuments.push(found); } - manager.SelectedDocuments.length = 0; - if (found) manager.SelectedDocuments.push(found); - } - export function SelectedDocuments(): Array { - return manager.SelectedDocuments; - } + export function SelectedDocuments(): Array { + return manager.SelectedDocuments; + } } diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss index befe175b5..080c9fa1e 100644 --- a/src/client/views/DocumentDecorations.scss +++ b/src/client/views/DocumentDecorations.scss @@ -2,13 +2,16 @@ #documentDecorations-container { position: absolute; + top: 0; + left:0; display: grid; z-index: 1000; grid-template-rows: 20px 8px 1fr 8px; - grid-template-columns: 8px 1fr 8px; + grid-template-columns: 8px 8px 1fr 8px; pointer-events: none; #documentDecorations-centerCont { + grid-column:3; background: none; } @@ -18,6 +21,24 @@ opacity: 0.8; } + #documentDecorations-topLeftResizer, + #documentDecorations-leftResizer, + #documentDecorations-bottomLeftResizer { + grid-column: 1 + } + + #documentDecorations-topResizer, + #documentDecorations-bottomResizer { + grid-column-start: 2; + grid-column-end: 4; + } + + #documentDecorations-bottomRightResizer, + #documentDecorations-topRightResizer, + #documentDecorations-rightResizer { + grid-column:4 + } + #documentDecorations-topLeftResizer, #documentDecorations-bottomRightResizer { cursor: nwse-resize; @@ -39,15 +60,19 @@ } .title{ background: lightblue; - grid-column-start:2; - grid-column-end: 4; + grid-column-start:3; + grid-column-end: 5; pointer-events: auto; } } .documentDecorations-minimizeButton { - background: rgb(250, 57, 9); + background:$alt-accent; + opacity: 0.8; + grid-column-start: 1; + grid-column-end: 3; pointer-events: all; + text-align: center; } .documentDecorations-background { background: lightblue; @@ -87,7 +112,8 @@ // } // } .linkFlyout { - grid-column: 1/4 + grid-column: 1/4; + margin-left: 25px; } .linkButton-empty:hover { @@ -102,6 +128,31 @@ cursor: pointer; } +.linkButton-linker { + position:absolute; + bottom:0px; + left: 0px; + height: 20px; + width: 20px; + margin-top: 10px; + margin-right: 5px; + border-radius: 50%; + opacity: 0.9; + pointer-events: auto; + color: $dark-color; + border: $dark-color 1px solid; + text-transform: uppercase; + letter-spacing: 2px; + font-size: 75%; + transition: transform 0.2s; + text-align: center; + display: flex; + justify-content: center; + align-items: center; +} +.linkButton-tray { + grid-column: 1/4; +} .linkButton-empty { height: 20px; width: 20px; diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index b74737ec9..a46087c9a 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -1,10 +1,11 @@ -import { action, computed, observable } from "mobx"; +import { action, computed, observable, trace, runInAction } from "mobx"; import { observer } from "mobx-react"; import { Key } from "../../fields/Key"; //import ContentEditable from 'react-contenteditable' import { KeyStore } from "../../fields/KeyStore"; import { ListField } from "../../fields/ListField"; import { NumberField } from "../../fields/NumberField"; +import { Document } from "../../fields/Document"; import { TextField } from "../../fields/TextField"; import { DragManager } from "../util/DragManager"; import { SelectionManager } from "../util/SelectionManager"; @@ -13,6 +14,7 @@ import './DocumentDecorations.scss'; import { DocumentView } from "./nodes/DocumentView"; import { LinkMenu } from "./nodes/LinkMenu"; import React = require("react"); +import { FieldWaiting } from "../../fields/Field"; const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; @@ -28,6 +30,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> private _linkBoxHeight = 30; private _titleHeight = 20; private _linkButton = React.createRef(); + private _linkerButton = React.createRef(); //@observable private _title: string = this._documents[0].props.Document.Title; @observable private _title: string = this._documents.length > 0 ? this._documents[0].props.Document.Title : ""; @observable private _fieldKey: Key = KeyStore.Title; @@ -174,18 +177,40 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> } } - onLinkButtonDown = (e: React.PointerEvent): void => { - // if () - // let linkMenu = new LinkMenu(SelectionManager.SelectedDocuments()[0]); - // linkMenu.Hidden = false; - console.log("down"); + onLinkerButtonDown = (e: React.PointerEvent): void => { + e.stopPropagation(); + document.removeEventListener("pointermove", this.onLinkerButtonMoved) + document.addEventListener("pointermove", this.onLinkerButtonMoved); + document.removeEventListener("pointerup", this.onLinkerButtonUp) + document.addEventListener("pointerup", this.onLinkerButtonUp); + } + onLinkerButtonUp = (e: PointerEvent): void => { + document.removeEventListener("pointermove", this.onLinkerButtonMoved) + document.removeEventListener("pointerup", this.onLinkerButtonUp) + e.stopPropagation(); + } + onLinkerButtonMoved = (e: PointerEvent): void => { + if (this._linkerButton.current != null) { + document.removeEventListener("pointermove", this.onLinkerButtonMoved) + document.removeEventListener("pointerup", this.onLinkerButtonUp) + let dragData = new DragManager.LinkDragData(SelectionManager.SelectedDocuments()[0]); + DragManager.StartLinkDrag(this._linkerButton.current, dragData, { + handlers: { + dragComplete: action(() => { }), + }, + hideSource: false + }) + } + e.stopPropagation(); + } + + onLinkButtonDown = (e: React.PointerEvent): void => { e.stopPropagation(); document.removeEventListener("pointermove", this.onLinkButtonMoved) document.addEventListener("pointermove", this.onLinkButtonMoved); document.removeEventListener("pointerup", this.onLinkButtonUp) document.addEventListener("pointerup", this.onLinkButtonUp); - } onLinkButtonUp = (e: PointerEvent): void => { @@ -194,18 +219,32 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> e.stopPropagation(); } - onLinkButtonMoved = (e: PointerEvent): void => { if (this._linkButton.current != null) { document.removeEventListener("pointermove", this.onLinkButtonMoved) - document.removeEventListener("pointerup", this.onLinkButtonUp) - let dragData = new DragManager.LinkDragData(SelectionManager.SelectedDocuments()[0]); - DragManager.StartLinkDrag(this._linkButton.current, dragData, { - handlers: { - dragComplete: action(() => { }), - }, - hideSource: false - }) + document.removeEventListener("pointerup", this.onLinkButtonUp); + + let sourceDoc = SelectionManager.SelectedDocuments()[0].props.Document; + let srcTarg = sourceDoc.GetT(KeyStore.Prototype, Document) + let draggedDocs = (srcTarg && srcTarg != FieldWaiting) ? + srcTarg.GetList(KeyStore.LinkedToDocs, [] as Document[]).map(linkDoc => + (linkDoc.GetT(KeyStore.LinkedToDocs, Document)) as Document) : []; + let draggedFromDocs = (srcTarg && srcTarg != FieldWaiting) ? + srcTarg.GetList(KeyStore.LinkedFromDocs, [] as Document[]).map(linkDoc => + (linkDoc.GetT(KeyStore.LinkedFromDocs, Document)) as Document) : []; + draggedDocs.push(...draggedFromDocs); + if (draggedDocs.length) { + let dragData = new DragManager.DocumentDragData(draggedDocs.map(d => { + let annot = d.GetT(KeyStore.AnnotationOn, Document); // bcz: ... needs to change ... the annotationOn document may not have been retrieved yet... + return annot && annot != FieldWaiting ? annot : d; + })); + DragManager.StartDocumentDrag([this._linkButton.current], dragData, { + handlers: { + dragComplete: action(() => { }), + }, + hideSource: false + }) + } } e.stopPropagation(); } @@ -298,7 +337,6 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> } getValue = (): string => { - console.log("value watched"); if (this._title === "changed" && this._documents.length > 0) { let field = this._documents[0].props.Document.Get(this._fieldKey); if (field instanceof TextField) { @@ -338,8 +376,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> linkButton = ( - + }>
{linkCount}
); @@ -361,7 +398,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> top: bounds.y - this._resizeBorderWidth / 2 - this._titleHeight, opacity: this._opacity }}> -
v
+
...
e.preventDefault()}>
e.preventDefault()}>
@@ -373,8 +410,8 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
e.preventDefault()}>
e.preventDefault()}>
-
{linkButton}
- +
{linkButton}
+
∞
) diff --git a/src/client/views/InkingCanvas.scss b/src/client/views/InkingCanvas.scss index 35c8ee942..c5a2a50cb 100644 --- a/src/client/views/InkingCanvas.scss +++ b/src/client/views/InkingCanvas.scss @@ -2,6 +2,8 @@ .inkingCanvas-paths-ink, .inkingCanvas-paths-markers, .inkingCanvas-noSelect, .inkingCanvas-canSelect { position: absolute; + top: 0; + left:0; width: 8192px; height: 8192px; cursor:"crosshair"; diff --git a/src/client/views/Main.scss b/src/client/views/Main.scss index 698a9c617..594803aab 100644 --- a/src/client/views/Main.scss +++ b/src/client/views/Main.scss @@ -7,6 +7,9 @@ body { overflow: hidden; font-family: $sans-serif; margin: 0; + position:absolute; + top: 0; + left:0; } #dash-title { @@ -158,11 +161,15 @@ button:hover { width:100%; height:100%; position:absolute; + top: 0; + left:0; } #mainContent-div { width:100%; height:100%; position:absolute; + top: 0; + left:0; } #add-options-content { display: table; diff --git a/src/client/views/collections/CollectionDockingView.scss b/src/client/views/collections/CollectionDockingView.scss index 2706c3272..583d50c5b 100644 --- a/src/client/views/collections/CollectionDockingView.scss +++ b/src/client/views/collections/CollectionDockingView.scss @@ -3,7 +3,7 @@ } .collectiondockingview-container { - position: relative; + position: absolute; top: 0; left: 0; overflow: hidden; diff --git a/src/client/views/collections/CollectionPDFView.scss b/src/client/views/collections/CollectionPDFView.scss index 0144625c1..0eca3f1cd 100644 --- a/src/client/views/collections/CollectionPDFView.scss +++ b/src/client/views/collections/CollectionPDFView.scss @@ -9,6 +9,8 @@ width: 100%; height: 100%; position: absolute; + top: 0; + left:0; } .collectionPdfView-backward { diff --git a/src/client/views/collections/CollectionVideoView.scss b/src/client/views/collections/CollectionVideoView.scss index cbb981b13..ed56ad268 100644 --- a/src/client/views/collections/CollectionVideoView.scss +++ b/src/client/views/collections/CollectionVideoView.scss @@ -3,6 +3,8 @@ width: 100%; height: 100%; position: absolute; + top: 0; + left:0; } .collectionVideoView-time{ diff --git a/src/client/views/collections/CollectionViewBase.tsx b/src/client/views/collections/CollectionViewBase.tsx index 2b0689800..daeca69e2 100644 --- a/src/client/views/collections/CollectionViewBase.tsx +++ b/src/client/views/collections/CollectionViewBase.tsx @@ -17,6 +17,8 @@ import { NumberField } from "../../../fields/NumberField"; import request = require("request"); import { ServerUtils } from "../../../server/ServerUtil"; import { Server } from "../../Server"; +import { CollectionDockingView } from "./CollectionDockingView"; +import { runReactions } from "mobx/lib/internal"; export interface CollectionViewProps { fieldKey: Key; @@ -92,6 +94,24 @@ export class CollectionViewBase extends React.Component e.stopPropagation(); return added; } + if (de.data instanceof DragManager.LinkDragData) { + let sourceDoc: Document = de.data.linkSourceDocumentView.props.Document; + if (sourceDoc) runInAction(() => { + let srcTarg = sourceDoc.GetT(KeyStore.Prototype, Document) + if (srcTarg && srcTarg != FieldWaiting) { + let linkDocs = srcTarg.GetList(KeyStore.LinkedToDocs, [] as Document[]); + linkDocs.map(linkDoc => { + let targDoc = linkDoc.GetT(KeyStore.LinkedToDocs, Document); + if (targDoc && targDoc != FieldWaiting) { + let dropdoc = targDoc.MakeDelegate(); + de.data.droppedDocuments.push(dropdoc); + this.props.addDocument(dropdoc, false); + } + }) + } + }) + return true; + } return false; } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx index e84f0c5ad..3dfd74ec8 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx @@ -23,10 +23,10 @@ export class CollectionFreeFormLinkView extends React.Component { if (super.drop(e, de)) { - if (de.data instanceof DragManager.DocumentDragData) { - let screenX = de.x - (de.data.xOffset as number || 0); - let screenY = de.y - (de.data.yOffset as number || 0); + let droppedDocs = de.data.droppedDocuments as Document[]; + let xoff = de.data.xOffset as number || 0; + let yoff = de.data.yOffset as number || 0; + if (droppedDocs && droppedDocs.length) { + let screenX = de.x - xoff; + let screenY = de.y - yoff; const [x, y] = this.getTransform().transformPoint(screenX, screenY); - let dragDoc = de.data.draggedDocuments[0]; + let dragDoc = de.data.droppedDocuments[0]; let dragX = dragDoc.GetNumber(KeyStore.X, 0); let dragY = dragDoc.GetNumber(KeyStore.Y, 0); - de.data.draggedDocuments.map(d => { + droppedDocs.map(d => { let docX = d.GetNumber(KeyStore.X, 0); let docY = d.GetNumber(KeyStore.Y, 0); d.SetNumber(KeyStore.X, x + (docX - dragX)); diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.scss b/src/client/views/collections/collectionFreeForm/MarqueeView.scss index 1ee3b244b..0b406e722 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.scss +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.scss @@ -1,6 +1,8 @@ .marqueeView { position: absolute; + top:0; + left:0; width:100%; height:100%; } diff --git a/src/client/views/collections/collectionFreeForm/PreviewCursor.scss b/src/client/views/collections/collectionFreeForm/PreviewCursor.scss index 21210be2b..7a67c29bf 100644 --- a/src/client/views/collections/collectionFreeForm/PreviewCursor.scss +++ b/src/client/views/collections/collectionFreeForm/PreviewCursor.scss @@ -3,9 +3,13 @@ color: black; position: absolute; transform-origin: left top; + top: 0; + left:0; pointer-events: none; } .previewCursorView { + top: 0; + left:0; position: absolute; width:100%; height:100%; diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index d52b662bd..1a0f0cbbd 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -66,8 +66,12 @@ export class CollectionFreeFormDocumentView extends React.Component } + panelWidth = () => this.props.Document.GetBoolean(KeyStore.Minimized, false) ? 10 : this.props.PanelWidth(); + panelHeight = () => this.props.Document.GetBoolean(KeyStore.Minimized, false) ? 10 : this.props.PanelHeight(); render() { return ( diff --git a/src/client/views/nodes/DocumentView.scss b/src/client/views/nodes/DocumentView.scss index 127a6b535..5126e69f9 100644 --- a/src/client/views/nodes/DocumentView.scss +++ b/src/client/views/nodes/DocumentView.scss @@ -2,6 +2,8 @@ .documentView-node { position: absolute; + top: 0; + left:0; background: $light-color; //overflow: hidden; &.minimized { diff --git a/src/client/views/nodes/PDFBox.scss b/src/client/views/nodes/PDFBox.scss index ad947afd5..830dfe6c6 100644 --- a/src/client/views/nodes/PDFBox.scss +++ b/src/client/views/nodes/PDFBox.scss @@ -1,12 +1,16 @@ .react-pdf__Page { transform-origin: left top; position: absolute; + top: 0; + left:0; } .react-pdf__Document { position: absolute; } .pdfBox-buttonTray { position:absolute; + top: 0; + left:0; z-index: 25; } .pdfBox-contentContainer { diff --git a/src/client/views/nodes/WebBox.scss b/src/client/views/nodes/WebBox.scss index a535b2638..c73bc0c47 100644 --- a/src/client/views/nodes/WebBox.scss +++ b/src/client/views/nodes/WebBox.scss @@ -2,6 +2,8 @@ .webBox-cont { padding: 0vw; position: absolute; + top: 0; + left:0; width: 100%; height: 100%; overflow: scroll; diff --git a/src/fields/Document.ts b/src/fields/Document.ts index 8e71019a4..92d03d765 100644 --- a/src/fields/Document.ts +++ b/src/fields/Document.ts @@ -9,415 +9,420 @@ import { Server } from "../client/Server"; import { Types } from "../server/Message"; import { UndoManager } from "../client/util/UndoManager"; import { HtmlField } from "./HtmlField"; +import { BooleanField } from "./BooleanField"; export class Document extends Field { - //TODO tfs: We should probably store FieldWaiting in fields when we request it from the server so that we don't set up multiple server gets for the same document and field - public fields: ObservableMap< - string, - { key: Key; field: Field } - > = new ObservableMap(); - public _proxies: ObservableMap = new ObservableMap(); - - constructor(id?: string, save: boolean = true) { - super(id); - - if (save) { - Server.UpdateField(this); + //TODO tfs: We should probably store FieldWaiting in fields when we request it from the server so that we don't set up multiple server gets for the same document and field + public fields: ObservableMap< + string, + { key: Key; field: Field } + > = new ObservableMap(); + public _proxies: ObservableMap = new ObservableMap(); + + constructor(id?: string, save: boolean = true) { + super(id); + + if (save) { + Server.UpdateField(this); + } } - } - UpdateFromServer(data: [string, string][]) { - for (const key in data) { - const element = data[key]; - this._proxies.set(element[0], element[1]); - } - } - - public Width = () => { - return this.GetNumber(KeyStore.Width, 0); - }; - public Height = () => { - return this.GetNumber( - KeyStore.Height, - this.GetNumber(KeyStore.NativeWidth, 0) - ? (this.GetNumber(KeyStore.NativeHeight, 0) / - this.GetNumber(KeyStore.NativeWidth, 0)) * - this.GetNumber(KeyStore.Width, 0) - : 0 - ); - }; - public Scale = () => { - return this.GetNumber(KeyStore.Scale, 1); - }; - - @computed - public get Title(): string { - let title = this.Get(KeyStore.Title, true); - if (title) - if (title != FieldWaiting && title instanceof TextField) - return title.Data; - else return "-waiting-"; - let parTitle = this.GetT(KeyStore.Title, TextField); - if (parTitle) - if (parTitle != FieldWaiting) return parTitle.Data + ".alias"; - else return "-waiting-.alias"; - return "-untitled-"; - } - - @computed - public get Fields() { - return this.fields; - } - - /** - * Get the field in the document associated with the given key. If the - * associated field has not yet been filled in from the server, a request - * to the server will automatically be sent, the value will be filled in - * when the request is completed, and {@link Field.ts#FieldWaiting} will be returned. - * @param key - The key of the value to get - * @param ignoreProto - If true, ignore any prototype this document - * might have and only search for the value on this immediate document. - * If false (default), search up the prototype chain, starting at this document, - * for a document that has a field associated with the given key, and return the first - * one found. - * - * @returns If the document does not have a field associated with the given key, returns `undefined`. - * If the document does have an associated field, but the field has not been fetched from the server, returns {@link Field.ts#FieldWaiting}. - * If the document does have an associated field, and the field has not been fetched from the server, returns the associated field. - */ - Get(key: Key, ignoreProto: boolean = false): FieldValue { - let field: FieldValue; - if (ignoreProto) { - if (this.fields.has(key.Id)) { - field = this.fields.get(key.Id)!.field; - } else if (this._proxies.has(key.Id)) { - Server.GetDocumentField(this, key); - /* - The field might have been instantly filled from the cache - Maybe we want to just switch back to returning the value - from Server.GetDocumentField if it's in the cache - */ - if (this.fields.has(key.Id)) { - field = this.fields.get(key.Id)!.field; - } else { - field = FieldWaiting; + UpdateFromServer(data: [string, string][]) { + for (const key in data) { + const element = data[key]; + this._proxies.set(element[0], element[1]); } - } - } else { - let doc: FieldValue = this; - while (doc && doc != FieldWaiting && field != FieldWaiting) { - let curField = doc.fields.get(key.Id); - let curProxy = doc._proxies.get(key.Id); - if (!curField || (curProxy && curField.field.Id !== curProxy)) { - if (curProxy) { - Server.GetDocumentField(doc, key); - /* + } + + public Width = () => { + return this.GetNumber(KeyStore.Width, 0); + }; + public Height = () => { + return this.GetNumber( + KeyStore.Height, + this.GetNumber(KeyStore.NativeWidth, 0) + ? (this.GetNumber(KeyStore.NativeHeight, 0) / + this.GetNumber(KeyStore.NativeWidth, 0)) * + this.GetNumber(KeyStore.Width, 0) + : 0 + ); + }; + public Scale = () => { + return this.GetNumber(KeyStore.Scale, 1); + }; + + @computed + public get Title(): string { + let title = this.Get(KeyStore.Title, true); + if (title) + if (title != FieldWaiting && title instanceof TextField) + return title.Data; + else return "-waiting-"; + let parTitle = this.GetT(KeyStore.Title, TextField); + if (parTitle) + if (parTitle != FieldWaiting) return parTitle.Data + ".alias"; + else return "-waiting-.alias"; + return "-untitled-"; + } + + @computed + public get Fields() { + return this.fields; + } + + /** + * Get the field in the document associated with the given key. If the + * associated field has not yet been filled in from the server, a request + * to the server will automatically be sent, the value will be filled in + * when the request is completed, and {@link Field.ts#FieldWaiting} will be returned. + * @param key - The key of the value to get + * @param ignoreProto - If true, ignore any prototype this document + * might have and only search for the value on this immediate document. + * If false (default), search up the prototype chain, starting at this document, + * for a document that has a field associated with the given key, and return the first + * one found. + * + * @returns If the document does not have a field associated with the given key, returns `undefined`. + * If the document does have an associated field, but the field has not been fetched from the server, returns {@link Field.ts#FieldWaiting}. + * If the document does have an associated field, and the field has not been fetched from the server, returns the associated field. + */ + Get(key: Key, ignoreProto: boolean = false): FieldValue { + let field: FieldValue; + if (ignoreProto) { + if (this.fields.has(key.Id)) { + field = this.fields.get(key.Id)!.field; + } else if (this._proxies.has(key.Id)) { + Server.GetDocumentField(this, key); + /* The field might have been instantly filled from the cache Maybe we want to just switch back to returning the value from Server.GetDocumentField if it's in the cache */ - if (this.fields.has(key.Id)) { - field = this.fields.get(key.Id)!.field; - } else { - field = FieldWaiting; + if (this.fields.has(key.Id)) { + field = this.fields.get(key.Id)!.field; + } else { + field = FieldWaiting; + } } - break; - } - if ( - doc.fields.has(KeyStore.Prototype.Id) || - doc._proxies.has(KeyStore.Prototype.Id) - ) { - doc = doc.GetPrototype(); - } else { - break; - } } else { - field = curField.field; - break; + let doc: FieldValue = this; + while (doc && doc != FieldWaiting && field != FieldWaiting) { + let curField = doc.fields.get(key.Id); + let curProxy = doc._proxies.get(key.Id); + if (!curField || (curProxy && curField.field.Id !== curProxy)) { + if (curProxy) { + Server.GetDocumentField(doc, key); + /* + The field might have been instantly filled from the cache + Maybe we want to just switch back to returning the value + from Server.GetDocumentField if it's in the cache + */ + if (this.fields.has(key.Id)) { + field = this.fields.get(key.Id)!.field; + } else { + field = FieldWaiting; + } + break; + } + if ( + doc.fields.has(KeyStore.Prototype.Id) || + doc._proxies.has(KeyStore.Prototype.Id) + ) { + doc = doc.GetPrototype(); + } else { + break; + } + } else { + field = curField.field; + break; + } + } + if (doc == FieldWaiting) field = FieldWaiting; } - } - if (doc == FieldWaiting) field = FieldWaiting; + + return field; } - return field; - } - - /** - * Tries to get the field associated with the given key, and if there is an - * associated field, calls the given callback with that field. - * @param key - The key of the value to get - * @param callback - A function that will be called with the associated field, if it exists, - * once it is fetched from the server (this may be immediately if the field has already been fetched). - * Note: The callback will not be called if there is no associated field. - * @returns `true` if the field exists on the document and `callback` will be called, and `false` otherwise - */ - GetAsync(key: Key, callback: (field: Opt) => void): void { - //TODO: This currently doesn't deal with prototypes - let field = this.fields.get(key.Id); - if (field && field.field) { - callback(field.field); - } else if (this._proxies.has(key.Id)) { - Server.GetDocumentField(this, key, callback); - } else if (this._proxies.has(KeyStore.Prototype.Id)) { - this.GetTAsync(KeyStore.Prototype, Document, proto => { - if (proto) { - proto.GetAsync(key, callback); + /** + * Tries to get the field associated with the given key, and if there is an + * associated field, calls the given callback with that field. + * @param key - The key of the value to get + * @param callback - A function that will be called with the associated field, if it exists, + * once it is fetched from the server (this may be immediately if the field has already been fetched). + * Note: The callback will not be called if there is no associated field. + * @returns `true` if the field exists on the document and `callback` will be called, and `false` otherwise + */ + GetAsync(key: Key, callback: (field: Opt) => void): void { + //TODO: This currently doesn't deal with prototypes + let field = this.fields.get(key.Id); + if (field && field.field) { + callback(field.field); + } else if (this._proxies.has(key.Id)) { + Server.GetDocumentField(this, key, callback); + } else if (this._proxies.has(KeyStore.Prototype.Id)) { + this.GetTAsync(KeyStore.Prototype, Document, proto => { + if (proto) { + proto.GetAsync(key, callback); + } else { + callback(undefined); + } + }); } else { - callback(undefined); + callback(undefined); } - }); - } else { - callback(undefined); } - } - - GetTAsync(key: Key, ctor: { new (): T }): Promise>; - GetTAsync( - key: Key, - ctor: { new (): T }, - callback: (field: Opt) => void - ): void; - GetTAsync( - key: Key, - ctor: { new (): T }, - callback?: (field: Opt) => void - ): Promise> | void { - let fn = (cb: (field: Opt) => void) => { - return this.GetAsync(key, field => { - cb(Cast(field, ctor)); - }); - }; - if (callback) { - fn(callback); - } else { - return new Promise(res => fn(res)); + + GetTAsync(key: Key, ctor: { new(): T }): Promise>; + GetTAsync( + key: Key, + ctor: { new(): T }, + callback: (field: Opt) => void + ): void; + GetTAsync( + key: Key, + ctor: { new(): T }, + callback?: (field: Opt) => void + ): Promise> | void { + let fn = (cb: (field: Opt) => void) => { + return this.GetAsync(key, field => { + cb(Cast(field, ctor)); + }); + }; + if (callback) { + fn(callback); + } else { + return new Promise(res => fn(res)); + } } - } - - /** - * Same as {@link Document#GetAsync}, except a field of the given type - * will be created if there is no field associated with the given key, - * or the field associated with the given key is not of the given type. - * @param ctor - Constructor of the field type to get. E.g., TextField, ImageField, etc. - */ - GetOrCreateAsync( - key: Key, - ctor: { new (): T }, - callback: (field: T) => void - ): void { - //This currently doesn't deal with prototypes - if (this._proxies.has(key.Id)) { - Server.GetDocumentField(this, key, field => { - if (field && field instanceof ctor) { - callback(field); + + /** + * Same as {@link Document#GetAsync}, except a field of the given type + * will be created if there is no field associated with the given key, + * or the field associated with the given key is not of the given type. + * @param ctor - Constructor of the field type to get. E.g., TextField, ImageField, etc. + */ + GetOrCreateAsync( + key: Key, + ctor: { new(): T }, + callback: (field: T) => void + ): void { + //This currently doesn't deal with prototypes + if (this._proxies.has(key.Id)) { + Server.GetDocumentField(this, key, field => { + if (field && field instanceof ctor) { + callback(field); + } else { + let newField = new ctor(); + this.Set(key, newField); + callback(newField); + } + }); } else { - let newField = new ctor(); - this.Set(key, newField); - callback(newField); + let newField = new ctor(); + this.Set(key, newField); + callback(newField); } - }); - } else { - let newField = new ctor(); - this.Set(key, newField); - callback(newField); } - } - - /** - * Same as {@link Document#Get}, except that it will additionally - * check if the field is of the given type. - * @param ctor - Constructor of the field type to get. E.g., `TextField`, `ImageField`, etc. - * @returns Same as {@link Document#Get}, except will return `undefined` - * if there is an associated field but it is of the wrong type. - */ - GetT( - key: Key, - ctor: { new (...args: any[]): T }, - ignoreProto: boolean = false - ): FieldValue { - var getfield = this.Get(key, ignoreProto); - if (getfield != FieldWaiting) { - return Cast(getfield, ctor); + + /** + * Same as {@link Document#Get}, except that it will additionally + * check if the field is of the given type. + * @param ctor - Constructor of the field type to get. E.g., `TextField`, `ImageField`, etc. + * @returns Same as {@link Document#Get}, except will return `undefined` + * if there is an associated field but it is of the wrong type. + */ + GetT( + key: Key, + ctor: { new(...args: any[]): T }, + ignoreProto: boolean = false + ): FieldValue { + var getfield = this.Get(key, ignoreProto); + if (getfield != FieldWaiting) { + return Cast(getfield, ctor); + } + return FieldWaiting; } - return FieldWaiting; - } - - GetOrCreate( - key: Key, - ctor: { new (): T }, - ignoreProto: boolean = false - ): T { - const field = this.GetT(key, ctor, ignoreProto); - if (field && field != FieldWaiting) { - return field; + + GetOrCreate( + key: Key, + ctor: { new(): T }, + ignoreProto: boolean = false + ): T { + const field = this.GetT(key, ctor, ignoreProto); + if (field && field != FieldWaiting) { + return field; + } + const newField = new ctor(); + this.Set(key, newField); + return newField; } - const newField = new ctor(); - this.Set(key, newField); - return newField; - } - - GetData( - key: Key, - ctor: { new (): U }, - defaultVal: T - ): T { - let val = this.Get(key); - let vval = val && val instanceof ctor ? val.Data : defaultVal; - return vval; - } - - GetHtml(key: Key, defaultVal: string): string { - return this.GetData(key, HtmlField, defaultVal); - } - - GetNumber(key: Key, defaultVal: number): number { - return this.GetData(key, NumberField, defaultVal); - } - - GetText(key: Key, defaultVal: string): string { - return this.GetData(key, TextField, defaultVal); - } - - GetList(key: Key, defaultVal: T[]): T[] { - return this.GetData>(key, ListField, defaultVal); - } - - @action - Set(key: Key, field: Field | undefined, setOnPrototype = false): void { - let old = this.fields.get(key.Id); - let oldField = old ? old.field : undefined; - if (setOnPrototype) { - this.SetOnPrototype(key, field); - } else { - if (field) { - this.fields.set(key.Id, { key, field }); - this._proxies.set(key.Id, field.Id); - // Server.AddDocumentField(this, key, field); - } else { - this.fields.delete(key.Id); - this._proxies.delete(key.Id); - // Server.DeleteDocumentField(this, key); - } - Server.UpdateField(this); + + GetData( + key: Key, + ctor: { new(): U }, + defaultVal: T + ): T { + let val = this.Get(key); + let vval = val && val instanceof ctor ? val.Data : defaultVal; + return vval; } - if (oldField || field) { - UndoManager.AddEvent({ - undo: () => this.Set(key, oldField, setOnPrototype), - redo: () => this.Set(key, field, setOnPrototype) - }); + + GetHtml(key: Key, defaultVal: string): string { + return this.GetData(key, HtmlField, defaultVal); } - } - - @action - SetOnPrototype(key: Key, field: Field | undefined): void { - this.GetTAsync(KeyStore.Prototype, Document, (f: Opt) => { - f && f.Set(key, field); - }); - } - - @action - SetDataOnPrototype( - key: Key, - value: T, - ctor: { new (): U }, - replaceWrongType = true - ) { - this.GetTAsync(KeyStore.Prototype, Document, (f: Opt) => { - f && f.SetData(key, value, ctor); - }); - } - - @action - SetData( - key: Key, - value: T, - ctor: { new (data: T): U }, - replaceWrongType = true - ) { - let field = this.Get(key, true); - if (field instanceof ctor) { - field.Data = value; - } else if (!field || replaceWrongType) { - let newField = new ctor(value); - // newField.Data = value; - this.Set(key, newField); + + GetBoolean(key: Key, defaultVal: boolean): boolean { + return this.GetData(key, BooleanField, defaultVal); } - } - - @action - SetText(key: Key, value: string, replaceWrongType = true) { - this.SetData(key, value, TextField, replaceWrongType); - } - - @action - SetNumber(key: Key, value: number, replaceWrongType = true) { - this.SetData(key, value, NumberField, replaceWrongType); - } - - GetPrototype(): FieldValue { - return this.GetT(KeyStore.Prototype, Document, true); - } - - GetAllPrototypes(): Document[] { - let protos: Document[] = []; - let doc: FieldValue = this; - while (doc && doc != FieldWaiting) { - protos.push(doc); - doc = doc.GetPrototype(); + + GetNumber(key: Key, defaultVal: number): number { + return this.GetData(key, NumberField, defaultVal); + } + + GetText(key: Key, defaultVal: string): string { + return this.GetData(key, TextField, defaultVal); + } + + GetList(key: Key, defaultVal: T[]): T[] { + return this.GetData>(key, ListField, defaultVal); + } + + @action + Set(key: Key, field: Field | undefined, setOnPrototype = false): void { + let old = this.fields.get(key.Id); + let oldField = old ? old.field : undefined; + if (setOnPrototype) { + this.SetOnPrototype(key, field); + } else { + if (field) { + this.fields.set(key.Id, { key, field }); + this._proxies.set(key.Id, field.Id); + // Server.AddDocumentField(this, key, field); + } else { + this.fields.delete(key.Id); + this._proxies.delete(key.Id); + // Server.DeleteDocumentField(this, key); + } + Server.UpdateField(this); + } + if (oldField || field) { + UndoManager.AddEvent({ + undo: () => this.Set(key, oldField, setOnPrototype), + redo: () => this.Set(key, field, setOnPrototype) + }); + } + } + + @action + SetOnPrototype(key: Key, field: Field | undefined): void { + this.GetTAsync(KeyStore.Prototype, Document, (f: Opt) => { + f && f.Set(key, field); + }); + } + + @action + SetDataOnPrototype( + key: Key, + value: T, + ctor: { new(): U }, + replaceWrongType = true + ) { + this.GetTAsync(KeyStore.Prototype, Document, (f: Opt) => { + f && f.SetData(key, value, ctor); + }); + } + + @action + SetData( + key: Key, + value: T, + ctor: { new(data: T): U }, + replaceWrongType = true + ) { + let field = this.Get(key, true); + if (field instanceof ctor) { + field.Data = value; + } else if (!field || replaceWrongType) { + let newField = new ctor(value); + // newField.Data = value; + this.Set(key, newField); + } + } + + @action + SetText(key: Key, value: string, replaceWrongType = true) { + this.SetData(key, value, TextField, replaceWrongType); + } + + @action + SetNumber(key: Key, value: number, replaceWrongType = true) { + this.SetData(key, value, NumberField, replaceWrongType); + } + + GetPrototype(): FieldValue { + return this.GetT(KeyStore.Prototype, Document, true); + } + + GetAllPrototypes(): Document[] { + let protos: Document[] = []; + let doc: FieldValue = this; + while (doc && doc != FieldWaiting) { + protos.push(doc); + doc = doc.GetPrototype(); + } + return protos; + } + + CreateAlias(id?: string): Document { + let alias = new Document(id); + this.GetTAsync(KeyStore.Prototype, Document, (f: Opt) => { + f && alias.Set(KeyStore.Prototype, f); + }); + + return alias; + } + + MakeDelegate(id?: string): Document { + let delegate = new Document(id); + + delegate.Set(KeyStore.Prototype, this); + + return delegate; + } + + ToScriptString(): string { + return ""; + } + + TrySetValue(value: any): boolean { + throw new Error("Method not implemented."); + } + GetValue() { + return this.Title; + var title = + (this._proxies.has(KeyStore.Title.Id) ? "???" : this.Title) + + "(" + + this.Id + + ")"; + return title; + //throw new Error("Method not implemented."); + } + Copy(): Field { + throw new Error("Method not implemented."); + } + + ToJson(): { type: Types; data: [string, string][]; _id: string } { + let fields: [string, string][] = []; + this._proxies.forEach((field, key) => { + if (field) { + fields.push([key, field as string]); + } + }); + + return { + type: Types.Document, + data: fields, + _id: this.Id + }; } - return protos; - } - - CreateAlias(id?: string): Document { - let alias = new Document(id); - this.GetTAsync(KeyStore.Prototype, Document, (f: Opt) => { - f && alias.Set(KeyStore.Prototype, f); - }); - - return alias; - } - - MakeDelegate(id?: string): Document { - let delegate = new Document(id); - - delegate.Set(KeyStore.Prototype, this); - - return delegate; - } - - ToScriptString(): string { - return ""; - } - - TrySetValue(value: any): boolean { - throw new Error("Method not implemented."); - } - GetValue() { - return this.Title; - var title = - (this._proxies.has(KeyStore.Title.Id) ? "???" : this.Title) + - "(" + - this.Id + - ")"; - return title; - //throw new Error("Method not implemented."); - } - Copy(): Field { - throw new Error("Method not implemented."); - } - - ToJson(): { type: Types; data: [string, string][]; _id: string } { - let fields: [string, string][] = []; - this._proxies.forEach((field, key) => { - if (field) { - fields.push([key, field as string]); - } - }); - - return { - type: Types.Document, - data: fields, - _id: this.Id - }; - } } -- cgit v1.2.3-70-g09d2 From 0403ee1f31d3f127a44aaabdfd21785d7efa6430 Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Fri, 5 Apr 2019 01:17:41 -0400 Subject: Fixed remaining linter warnings --- src/client/northstar/core/BaseObject.ts | 2 +- .../northstar/core/attribute/AttributeModel.ts | 4 +- .../core/attribute/AttributeTransformationModel.ts | 2 +- .../core/attribute/CalculatedAttributeModel.ts | 4 +- src/client/northstar/core/filter/FilterModel.ts | 6 +- .../northstar/core/filter/ValueComparision.ts | 8 +- src/client/northstar/dash-fields/HistogramField.ts | 8 +- .../dash-nodes/HistogramBinPrimitiveCollection.ts | 46 ++++----- src/client/northstar/dash-nodes/HistogramBox.tsx | 12 +-- .../dash-nodes/HistogramBoxPrimitives.tsx | 18 ++-- .../dash-nodes/HistogramLabelPrimitives.tsx | 10 +- src/client/northstar/manager/Gateway.ts | 8 +- src/client/northstar/model/ModelExtensions.ts | 14 +-- src/client/northstar/model/ModelHelpers.ts | 10 +- .../model/binRanges/DateTimeVisualBinRange.ts | 24 ++--- .../northstar/model/binRanges/VisualBinRange.ts | 4 - .../model/binRanges/VisualBinRangeHelper.ts | 7 +- .../northstar/model/idea/MetricTypeMapping.ts | 28 +++--- src/client/northstar/operations/BaseOperation.ts | 8 +- .../northstar/operations/HistogramOperation.ts | 2 +- src/client/northstar/utils/ArrayUtil.ts | 14 +-- src/client/northstar/utils/GeometryUtil.ts | 2 +- src/client/northstar/utils/MathUtil.ts | 12 +-- src/client/northstar/utils/SizeConverter.ts | 4 +- src/client/northstar/utils/Utils.ts | 12 +-- src/client/views/DocumentDecorations.tsx | 4 +- src/client/views/Main.tsx | 4 +- .../views/collections/CollectionBaseView.tsx | 8 +- .../views/collections/CollectionDockingView.tsx | 30 +++--- src/client/views/collections/CollectionPDFView.tsx | 2 +- .../views/collections/CollectionSchemaView.tsx | 2 +- .../views/collections/CollectionVideoView.tsx | 4 +- src/client/views/collections/CollectionView.tsx | 2 +- .../views/collections/CollectionViewBase.tsx | 4 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 4 +- .../collections/collectionFreeForm/MarqueeView.tsx | 12 +-- .../collectionFreeForm/PreviewCursor.tsx | 2 +- src/client/views/nodes/Annotation.tsx | 108 ++++++++++----------- src/client/views/nodes/AudioBox.tsx | 2 +- src/client/views/nodes/DocumentContentsView.tsx | 2 +- src/client/views/nodes/KeyValueBox.tsx | 6 +- src/client/views/nodes/LinkBox.tsx | 2 +- src/client/views/nodes/LinkMenu.tsx | 2 +- src/client/views/nodes/VideoBox.tsx | 2 +- src/client/views/nodes/WebBox.tsx | 2 +- src/fields/AudioField.ts | 2 +- src/fields/BasicField.ts | 2 +- src/fields/ImageField.ts | 2 +- src/fields/ListField.ts | 10 +- src/fields/PDFField.ts | 2 +- src/fields/VideoField.ts | 2 +- src/server/index.ts | 2 +- 52 files changed, 245 insertions(+), 250 deletions(-) (limited to 'src/client/northstar') diff --git a/src/client/northstar/core/BaseObject.ts b/src/client/northstar/core/BaseObject.ts index e9e766e31..f1761e643 100644 --- a/src/client/northstar/core/BaseObject.ts +++ b/src/client/northstar/core/BaseObject.ts @@ -4,7 +4,7 @@ import { IDisposable } from '../utils/IDisposable' export class BaseObject implements IEquatable, IDisposable { public Equals(other: Object): boolean { - return this == other; + return this === other; } public Dispose(): void { diff --git a/src/client/northstar/core/attribute/AttributeModel.ts b/src/client/northstar/core/attribute/AttributeModel.ts index 124a5b45a..230bfecc8 100644 --- a/src/client/northstar/core/attribute/AttributeModel.ts +++ b/src/client/northstar/core/attribute/AttributeModel.ts @@ -34,7 +34,7 @@ export class ColumnAttributeModel extends AttributeModel { } public Equals(other: ColumnAttributeModel): boolean { - return this.Attribute.rawName == other.Attribute.rawName; + return this.Attribute.rawName === other.Attribute.rawName; } } @@ -105,7 +105,7 @@ export class BackendAttributeModel extends AttributeModel { } public Equals(other: BackendAttributeModel): boolean { - return this.Id == other.Id; + return this.Id === other.Id; } } \ No newline at end of file diff --git a/src/client/northstar/core/attribute/AttributeTransformationModel.ts b/src/client/northstar/core/attribute/AttributeTransformationModel.ts index cc5aa7154..f50b78d51 100644 --- a/src/client/northstar/core/attribute/AttributeTransformationModel.ts +++ b/src/client/northstar/core/attribute/AttributeTransformationModel.ts @@ -41,7 +41,7 @@ export class AttributeTransformationModel implements IEquatable { } public Equals(other: AttributeTransformationModel): boolean { - return this.AggregateFunction == other.AggregateFunction && + return this.AggregateFunction === other.AggregateFunction && this.AttributeModel.Equals(other.AttributeModel); } } \ No newline at end of file diff --git a/src/client/northstar/core/attribute/CalculatedAttributeModel.ts b/src/client/northstar/core/attribute/CalculatedAttributeModel.ts index ab96c794d..0b8e0d12c 100644 --- a/src/client/northstar/core/attribute/CalculatedAttributeModel.ts +++ b/src/client/northstar/core/attribute/CalculatedAttributeModel.ts @@ -11,7 +11,7 @@ export class CalculatedAttributeManager { public static CreateBackendAttributeModel(id: string, dataType: DataType, displayName: string, codeName: string, visualizationHints: VisualizationHint[]): BackendAttributeModel { var filtered = this.AllCalculatedAttributes.filter(am => { if (am instanceof BackendAttributeModel && - am.Id == id) { + am.Id === id) { return true; } return false; @@ -27,7 +27,7 @@ export class CalculatedAttributeManager { public static CreateCodeAttributeModel(code: string, codeName: string, visualizationHints: VisualizationHint[]): CodeAttributeModel { var filtered = this.AllCalculatedAttributes.filter(am => { if (am instanceof CodeAttributeModel && - am.CodeName == codeName) { + am.CodeName === codeName) { return true; } return false; diff --git a/src/client/northstar/core/filter/FilterModel.ts b/src/client/northstar/core/filter/FilterModel.ts index aee99d2b6..20fca77f5 100644 --- a/src/client/northstar/core/filter/FilterModel.ts +++ b/src/client/northstar/core/filter/FilterModel.ts @@ -46,16 +46,16 @@ export class FilterModel { 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(" || ") + ")"; + 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) { + if (filterDoc && filterDoc !== FieldWaiting && filterDoc instanceof Document) { let filterHistogram = filterDoc.GetT(KeyStore.Data, HistogramField); - if (filterHistogram && filterHistogram != FieldWaiting) { + if (filterHistogram && filterHistogram !== FieldWaiting) { if (!visitedFilterProviders.has(filterHistogram.Data)) { let child = FilterModel.GetFilterModelsRecursive(filterHistogram.Data, visitedFilterProviders, filterModels, false); if (child !== "") { diff --git a/src/client/northstar/core/filter/ValueComparision.ts b/src/client/northstar/core/filter/ValueComparision.ts index 1e729d06e..1a3e461f5 100644 --- a/src/client/northstar/core/filter/ValueComparision.ts +++ b/src/client/northstar/core/filter/ValueComparision.ts @@ -20,7 +20,7 @@ export class ValueComparison { if (this.Predicate !== (other as ValueComparison).Predicate) return false; let isComplex = (typeof this.Value === "object"); - if (!isComplex && this.Value != (other as ValueComparison).Value) + if (!isComplex && this.Value !== (other as ValueComparison).Value) return false; if (isComplex && !this.Value.Equals((other as ValueComparison).Value)) return false; @@ -58,13 +58,13 @@ export class ValueComparison { var rawName = this.attributeModel.CodeName; switch (this.Predicate) { case Predicate.STARTS_WITH: - ret += rawName + " != null && " + rawName + ".StartsWith(" + val + ") "; + ret += rawName + " !== null && " + rawName + ".StartsWith(" + val + ") "; return ret; case Predicate.ENDS_WITH: - ret += rawName + " != null && " + rawName + ".EndsWith(" + val + ") "; + ret += rawName + " !== null && " + rawName + ".EndsWith(" + val + ") "; return ret; case Predicate.CONTAINS: - ret += rawName + " != null && " + rawName + ".Contains(" + val + ") "; + ret += rawName + " !== null && " + rawName + ".Contains(" + val + ") "; return ret; default: ret += rawName + " " + op + " " + val + " "; diff --git a/src/client/northstar/dash-fields/HistogramField.ts b/src/client/northstar/dash-fields/HistogramField.ts index 90be70b80..f939ccd83 100644 --- a/src/client/northstar/dash-fields/HistogramField.ts +++ b/src/client/northstar/dash-fields/HistogramField.ts @@ -16,7 +16,7 @@ export class HistogramField extends BasicField { omitKeys(obj: any, keys: any) { var dup: any = {}; for (var key in obj) { - if (keys.indexOf(key) == -1) { + if (keys.indexOf(key) === -1) { dup[key] = obj[key]; } } @@ -54,13 +54,13 @@ export class HistogramField extends BasicField { let schema = CurrentUserUtils.GetNorthstarSchema(jp.SchemaName); if (schema) { CurrentUserUtils.GetAllNorthstarColumnAttributes(schema).map(attr => { - if (attr.displayName == jp.X.AttributeModel.Attribute.DisplayName) { + 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) { + 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) { + if (attr.displayName === jp.V.AttributeModel.Attribute.DisplayName) { V = new AttributeTransformationModel(new ColumnAttributeModel(attr), jp.V.AggregateFunction); } }); diff --git a/src/client/northstar/dash-nodes/HistogramBinPrimitiveCollection.ts b/src/client/northstar/dash-nodes/HistogramBinPrimitiveCollection.ts index 43e768c62..cdae90c8b 100644 --- a/src/client/northstar/dash-nodes/HistogramBinPrimitiveCollection.ts +++ b/src/client/northstar/dash-nodes/HistogramBinPrimitiveCollection.ts @@ -48,28 +48,28 @@ export class HistogramBinPrimitiveCollection { // 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); + 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) { + 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) { + 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) { + 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) { + 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); @@ -79,19 +79,19 @@ export class HistogramBinPrimitiveCollection { return 0; }, 0); this.BinPrimitives = this.BinPrimitives.reverse(); - var f = this.BinPrimitives.filter(b => b.BrushIndex == allBrushIndex); + 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)); + 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; + return aggResult !== undefined && aggResult > prev ? aggResult : prev; }, Number.MIN_VALUE) }; } @@ -99,7 +99,7 @@ export class HistogramBinPrimitiveCollection { private createHeatmapBinPrimitives(bin: Bin, brush: Brush, brushFactorSum: number): number { let unNormalizedValue = this.getBinValue(2, bin, brush.brushIndex!); - if (unNormalizedValue == undefined) + if (unNormalizedValue === undefined) return brushFactorSum; var normalizedValue = (unNormalizedValue - this._histoBox.ValueRange[0]) / (Math.abs((this._histoBox.ValueRange[1] - this._histoBox.ValueRange[0])) < HistogramBinPrimitiveCollection.TOLERANCE ? @@ -112,7 +112,7 @@ export class HistogramBinPrimitiveCollection { let [yFrom, yTo] = this.sizeConverter.DataToScreenYAxisRange(this._histoBox.VisualBinRanges, 1, bin); var returnBrushFactorSum = brushFactorSum; - if (allUnNormalizedValue != undefined) { + if (allUnNormalizedValue !== undefined) { var brushFactor = (unNormalizedValue / allUnNormalizedValue); returnBrushFactorSum += brushFactor; returnBrushFactorSum = Math.min(returnBrushFactorSum, 1.0); @@ -141,11 +141,11 @@ export class HistogramBinPrimitiveCollection { private createSinglePointChartBinPrimitives(bin: Bin, brush: Brush): number { let unNormalizedValue = this.getBinValue(2, bin, brush.brushIndex!); - if (unNormalizedValue != undefined) { + 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) + 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; @@ -153,7 +153,7 @@ export class HistogramBinPrimitiveCollection { private createVerticalBarChartBinPrimitives(bin: Bin, brush: Brush, binBrushMaxAxis: number, normalization: number): number { let dataValue = this.getBinValue(1, bin, brush.brushIndex!); - if (dataValue != undefined) { + 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); @@ -163,14 +163,14 @@ export class HistogramBinPrimitiveCollection { 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); + 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) { + 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); @@ -181,15 +181,15 @@ export class HistogramBinPrimitiveCollection { 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); + 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); + 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; + return dataValue !== null && dataValue.hasResult ? dataValue.result : undefined; } private getMargin(bin: Bin, brush: Brush, axis: AttributeTransformationModel) { @@ -218,13 +218,13 @@ export class HistogramBinPrimitiveCollection { private baseColorFromBrush(brush: Brush): number { let bc = StyleConstants.BRUSH_COLORS; - if (brush.brushIndex == ModelHelpers.RestBrushIndex(this.histoResult)) { + if (brush.brushIndex === ModelHelpers.RestBrushIndex(this.histoResult)) { return StyleConstants.HIGHLIGHT_COLOR; } - else if (brush.brushIndex == ModelHelpers.OverlapBrushIndex(this.histoResult)) { + else if (brush.brushIndex === ModelHelpers.OverlapBrushIndex(this.histoResult)) { return StyleConstants.OVERLAP_COLOR; } - else if (brush.brushIndex == ModelHelpers.AllBrushIndex(this.histoResult)) { + else if (brush.brushIndex === ModelHelpers.AllBrushIndex(this.histoResult)) { return 0x00ff00; } else if (bc.length > 0) { diff --git a/src/client/northstar/dash-nodes/HistogramBox.tsx b/src/client/northstar/dash-nodes/HistogramBox.tsx index 5938bf9b1..c9658d741 100644 --- a/src/client/northstar/dash-nodes/HistogramBox.tsx +++ b/src/client/northstar/dash-nodes/HistogramBox.tsx @@ -55,7 +55,7 @@ export class HistogramBox extends React.Component { dropX = (e: Event, de: DragManager.DropEvent) => { if (de.data instanceof DragManager.DocumentDragData) { let h = de.data.draggedDocuments[0].GetT(KeyStore.Data, HistogramField); - if (h && h != FieldWaiting) { + if (h && h !== FieldWaiting) { this.HistoOp.X = h.Data.X; } e.stopPropagation(); @@ -66,7 +66,7 @@ export class HistogramBox extends React.Component { dropY = (e: Event, de: DragManager.DropEvent) => { if (de.data instanceof DragManager.DocumentDragData) { let h = de.data.draggedDocuments[0].GetT(KeyStore.Data, HistogramField); - if (h && h != FieldWaiting) { + if (h && h !== FieldWaiting) { this.HistoOp.Y = h.Data.X; } e.stopPropagation(); @@ -76,11 +76,11 @@ 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); + 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); + this.HistoOp.Y = new AttributeTransformationModel(this.HistoOp.Y.AttributeModel, this.HistoOp.Y.AggregateFunction === AggregateFunction.None ? AggregateFunction.Count : AggregateFunction.None); } componentDidMount() { @@ -119,7 +119,7 @@ export class HistogramBox extends React.Component { if (catalog) { this.props.Document.GetTAsync(this.props.fieldKey, HistogramField).then((histoOp: Opt) => runInAction(() => { this.HistoOp = histoOp ? histoOp.Data : HistogramOperation.Empty; - if (this.HistoOp != HistogramOperation.Empty) { + if (this.HistoOp !== HistogramOperation.Empty) { reaction(() => this.props.Document.GetList(KeyStore.LinkedFromDocs, []), (docs: Document[]) => this.HistoOp.Links.splice(0, this.HistoOp.Links.length, ...docs), { fireImmediately: true }); reaction(() => this.props.Document.GetList(KeyStore.BrushingDocs, []).length, () => { @@ -128,7 +128,7 @@ export class HistogramBox extends React.Component { 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[]); - return { l: brush, b: brushed[0].Id == proto.Id ? brushed[1] : brushed[0] } + return { l: brush, b: brushed[0].Id === proto.Id ? brushed[1] : brushed[0] } })); }, { 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 e9adb3ce5..66d31846c 100644 --- a/src/client/northstar/dash-nodes/HistogramBoxPrimitives.tsx +++ b/src/client/northstar/dash-nodes/HistogramBoxPrimitives.tsx @@ -44,7 +44,7 @@ export class HistogramBoxPrimitives extends React.Component bp.BrushIndex == allBrushIndex); + 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); @@ -63,9 +63,9 @@ export class HistogramBoxPrimitives extends React.Component { 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)); + 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[]); } @@ -86,8 +86,8 @@ export class HistogramBoxPrimitives extends React.Component); return this.drawEntity(xFrom, yFrom, line); } @@ -102,10 +102,10 @@ export class HistogramBoxPrimitives extends React.Component { if (e.button == 0) tapHandler() }} + let rect = (
{ if (e.button === 0) tapHandler() }} style={{ - borderBottomStyle: barAxis == 1 ? "none" : "solid", - borderLeftStyle: barAxis == 0 ? "none" : "solid", + borderBottomStyle: barAxis === 1 ? "none" : "solid", + borderLeftStyle: barAxis === 0 ? "none" : "solid", width: `${widthPercent}%`, height: `${heightPercent}%`, background: color ? `${LABColor.RGBtoHexString(color)}` : "" diff --git a/src/client/northstar/dash-nodes/HistogramLabelPrimitives.tsx b/src/client/northstar/dash-nodes/HistogramLabelPrimitives.tsx index 93b237deb..dd62e9146 100644 --- a/src/client/northstar/dash-nodes/HistogramLabelPrimitives.tsx +++ b/src/client/northstar/dash-nodes/HistogramLabelPrimitives.tsx @@ -34,7 +34,7 @@ export class HistogramLabelPrimitives extends React.ComponentFontStyles.AxisLabel.fontSize + 5))); sc.MaxLabelSizes[axis].coords[axis] + 5); @@ -47,17 +47,17 @@ export class HistogramLabelPrimitives extends React.Component -
+
{label}
diff --git a/src/client/northstar/manager/Gateway.ts b/src/client/northstar/manager/Gateway.ts index 3e72a50ae..ba6fe2ad5 100644 --- a/src/client/northstar/manager/Gateway.ts +++ b/src/client/northstar/manager/Gateway.ts @@ -49,7 +49,7 @@ export class Gateway { public async Compile(data: any): Promise { const json = await this.MakePostJsonRequest("compile", data); - if (json != null) { + if (json !== null) { const cr = CompileResults.fromJS(json); return cr; } @@ -108,7 +108,7 @@ export class Gateway { public async StartOperation(data: any): Promise { const json = await this.MakePostJsonRequest("operation", data); - if (json != null) { + if (json !== null) { const or = OperationReference.fromJS(json); return or; } @@ -116,7 +116,7 @@ export class Gateway { public async GetResult(data: any): Promise { const json = await this.MakePostJsonRequest("result", data); - if (json != null) { + if (json !== null) { const res = Result.fromJS(json); return res; } @@ -163,7 +163,7 @@ export class Gateway { public static ConstructUrl(appendix: string): string { let base = Settings.Instance.ServerUrl; - if (base.slice(-1) == "/") { + if (base.slice(-1) === "/") { base = base.slice(0, -1); } let url = base + "/" + Settings.Instance.ServerApiPath + "/" + appendix; diff --git a/src/client/northstar/model/ModelExtensions.ts b/src/client/northstar/model/ModelExtensions.ts index 9fcba7f1c..e4bf77ed8 100644 --- a/src/client/northstar/model/ModelExtensions.ts +++ b/src/client/northstar/model/ModelExtensions.ts @@ -3,23 +3,23 @@ import { Utils } from '../utils/Utils' import { FilterModel } from '../core/filter/FilterModel' -(SingleDimensionAggregateParameters as any).prototype["Equals"] = function (other: Object) { +(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; + if (!((this as SingleDimensionAggregateParameters).attributeParameters! as any).Equals((other as SingleDimensionAggregateParameters).attributeParameters)) return false; return true; } { - (AttributeParameters as any).prototype["Equals"] = function (other: AttributeParameters) { + (AttributeParameters as any).prototype.Equals = function (other: AttributeParameters) { return (this).constructor.name === (other).constructor.name && this.rawName === other.rawName; } } { - (Solution as any).prototype["Equals"] = function (other: Object) { + (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; @@ -27,11 +27,11 @@ import { FilterModel } from '../core/filter/FilterModel' } { - (MarginAggregateParameters as any).prototype["Equals"] = function (other: Object) { + (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 SingleDimensionAggregateParameters).attributeParameters! as any).Equals((other as SingleDimensionAggregateParameters).attributeParameters!)) return false; if ((this as MarginAggregateParameters).aggregateFunction !== (other as MarginAggregateParameters).aggregateFunction) return false; return true; @@ -39,7 +39,7 @@ import { FilterModel } from '../core/filter/FilterModel' } { - (Brush as any).prototype["Equals"] = function (other: Object) { + (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; diff --git a/src/client/northstar/model/ModelHelpers.ts b/src/client/northstar/model/ModelHelpers.ts index d0711fb69..1a58e6180 100644 --- a/src/client/northstar/model/ModelHelpers.ts +++ b/src/client/northstar/model/ModelHelpers.ts @@ -16,7 +16,7 @@ export class ModelHelpers { public static CreateAggregateKey(distinctAttributeParameters: AttributeParameters | undefined, atm: AttributeTransformationModel, histogramResult: HistogramResult, brushIndex: number, aggParameters?: SingleDimensionAggregateParameters): AggregateKey { { - if (aggParameters == undefined) { + if (aggParameters === undefined) { aggParameters = ModelHelpers.GetAggregateParameter(distinctAttributeParameters, atm); } else { @@ -146,7 +146,7 @@ export class ModelHelpers { } public static GetAggregateResult(bin: Bin, aggregateKey: AggregateKey) { - if (aggregateKey.aggregateParameterIndex == -1 || aggregateKey.brushIndex == -1) { + if (aggregateKey.aggregateParameterIndex === -1 || aggregateKey.brushIndex === -1) { return null; } return bin.aggregateResults![aggregateKey.aggregateParameterIndex! * bin.ySize! + aggregateKey.brushIndex!]; @@ -157,9 +157,9 @@ export class ModelHelpers { var ret = new Array(); ret.push(AggregateFunction.None); ret.push(AggregateFunction.Count); - if (atm.AttributeModel.DataType == DataType.Float || - atm.AttributeModel.DataType == DataType.Double || - atm.AttributeModel.DataType == DataType.Int) { + if (atm.AttributeModel.DataType === DataType.Float || + atm.AttributeModel.DataType === DataType.Double || + atm.AttributeModel.DataType === DataType.Int) { ret.push(AggregateFunction.Avg); ret.push(AggregateFunction.Sum); } diff --git a/src/client/northstar/model/binRanges/DateTimeVisualBinRange.ts b/src/client/northstar/model/binRanges/DateTimeVisualBinRange.ts index 9313fb1a7..f5872aa4c 100644 --- a/src/client/northstar/model/binRanges/DateTimeVisualBinRange.ts +++ b/src/client/northstar/model/binRanges/DateTimeVisualBinRange.ts @@ -39,24 +39,24 @@ export class DateTimeVisualBinRange extends VisualBinRange { public GetLabel(value: number): string { var dt = DateTimeVisualBinRange.TicksToDate(value); - if (this.DataBinRange.step!.dateTimeStepGranularity == DateTimeStepGranularity.Second || - this.DataBinRange.step!.dateTimeStepGranularity == DateTimeStepGranularity.Minute) { + 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) { + 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) { + 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) { + 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) { + else if (this.DataBinRange.step!.dateTimeStepGranularity === DateTimeStepGranularity.Year) { return "" + dt.getFullYear(); } return "n/a"; @@ -82,22 +82,22 @@ export class DateTimeVisualBinRange extends VisualBinRange { 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) { + if (dateTimeStep.dateTimeStepGranularity === DateTimeStepGranularity.Second) { returnDate = new Date(copiedDate.setSeconds(copiedDate.getSeconds() + dateTimeStep.dateTimeStepValue!)); } - else if (dateTimeStep.dateTimeStepGranularity == DateTimeStepGranularity.Minute) { + else if (dateTimeStep.dateTimeStepGranularity === DateTimeStepGranularity.Minute) { returnDate = new Date(copiedDate.setMinutes(copiedDate.getMinutes() + dateTimeStep.dateTimeStepValue!)); } - else if (dateTimeStep.dateTimeStepGranularity == DateTimeStepGranularity.Hour) { + else if (dateTimeStep.dateTimeStepGranularity === DateTimeStepGranularity.Hour) { returnDate = new Date(copiedDate.setHours(copiedDate.getHours() + dateTimeStep.dateTimeStepValue!)); } - else if (dateTimeStep.dateTimeStepGranularity == DateTimeStepGranularity.Day) { + else if (dateTimeStep.dateTimeStepGranularity === DateTimeStepGranularity.Day) { returnDate = new Date(copiedDate.setDate(copiedDate.getDate() + dateTimeStep.dateTimeStepValue!)); } - else if (dateTimeStep.dateTimeStepGranularity == DateTimeStepGranularity.Month) { + else if (dateTimeStep.dateTimeStepGranularity === DateTimeStepGranularity.Month) { returnDate = new Date(copiedDate.setMonth(copiedDate.getMonth() + dateTimeStep.dateTimeStepValue!)); } - else if (dateTimeStep.dateTimeStepGranularity == DateTimeStepGranularity.Year) { + else if (dateTimeStep.dateTimeStepGranularity === DateTimeStepGranularity.Year) { returnDate = new Date(copiedDate.setFullYear(copiedDate.getFullYear() + dateTimeStep.dateTimeStepValue!)); } return DateTimeVisualBinRange.DateToTicks(returnDate); diff --git a/src/client/northstar/model/binRanges/VisualBinRange.ts b/src/client/northstar/model/binRanges/VisualBinRange.ts index f53008f9a..a0766e494 100644 --- a/src/client/northstar/model/binRanges/VisualBinRange.ts +++ b/src/client/northstar/model/binRanges/VisualBinRange.ts @@ -2,10 +2,6 @@ import { BinLabel } from '../../model/idea/idea' export abstract class VisualBinRange { - constructor() { - - } - public abstract AddStep(value: number): number; public abstract GetValueFromIndex(index: number): number; diff --git a/src/client/northstar/model/binRanges/VisualBinRangeHelper.ts b/src/client/northstar/model/binRanges/VisualBinRangeHelper.ts index 53d585bb4..63ee61909 100644 --- a/src/client/northstar/model/binRanges/VisualBinRangeHelper.ts +++ b/src/client/northstar/model/binRanges/VisualBinRangeHelper.ts @@ -39,8 +39,7 @@ export class VisualBinRangeHelper { 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++) { - var brush = histoResult.brushes![b]; + for (const brush of histoResult.brushes!) { aggregateKey.brushIndex = brush.brushIndex; for (var key in histoResult.bins) { if (histoResult.bins.hasOwnProperty(key)) { @@ -56,12 +55,12 @@ export class VisualBinRangeHelper { let visualBinRange = QuantitativeVisualBinRange.Initialize(minValue, maxValue, 10, false); - if (chartType == ChartType.HorizontalBar || chartType == ChartType.VerticalBar) { + 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) { + else if (chartType === ChartType.SinglePoint) { visualBinRange = QuantitativeVisualBinRange.Initialize(Math.min(0, minValue), Math.max(0, maxValue), SETTINGS_X_BINS, false); } diff --git a/src/client/northstar/model/idea/MetricTypeMapping.ts b/src/client/northstar/model/idea/MetricTypeMapping.ts index 11e0c871a..e9759cf16 100644 --- a/src/client/northstar/model/idea/MetricTypeMapping.ts +++ b/src/client/northstar/model/idea/MetricTypeMapping.ts @@ -5,20 +5,20 @@ import { Dictionary } from 'typescript-collections'; export class MetricTypeMapping { public static GetMetricInterpretation(metricType: MetricType): MetricInterpretation { - if (metricType == MetricType.Accuracy || - metricType == MetricType.F1 || - metricType == MetricType.F1Macro || - metricType == MetricType.F1Micro || - metricType == MetricType.JaccardSimilarityScore || - metricType == MetricType.ObjectDetectionAveragePrecision || - metricType == MetricType.Precision || - metricType == MetricType.PrecisionAtTopK || - metricType == MetricType.NormalizedMutualInformation || - metricType == MetricType.Recall || - metricType == MetricType.RocAucMacro || - metricType == MetricType.RocAuc || - metricType == MetricType.RocAucMicro || - metricType == MetricType.RSquared) { + if (metricType === MetricType.Accuracy || + metricType === MetricType.F1 || + metricType === MetricType.F1Macro || + metricType === MetricType.F1Micro || + metricType === MetricType.JaccardSimilarityScore || + metricType === MetricType.ObjectDetectionAveragePrecision || + metricType === MetricType.Precision || + metricType === MetricType.PrecisionAtTopK || + metricType === MetricType.NormalizedMutualInformation || + metricType === MetricType.Recall || + metricType === MetricType.RocAucMacro || + metricType === MetricType.RocAuc || + metricType === MetricType.RocAucMicro || + metricType === MetricType.RSquared) { return MetricInterpretation.HigherIsBetter; } return MetricInterpretation.LowerIsBetter; diff --git a/src/client/northstar/operations/BaseOperation.ts b/src/client/northstar/operations/BaseOperation.ts index f545b2c58..a14337763 100644 --- a/src/client/northstar/operations/BaseOperation.ts +++ b/src/client/northstar/operations/BaseOperation.ts @@ -29,11 +29,11 @@ export abstract class BaseOperation { // 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(" || ") + ")"; + // 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)) { + // 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); // } @@ -99,8 +99,8 @@ export abstract class BaseOperation { 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 (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."); diff --git a/src/client/northstar/operations/HistogramOperation.ts b/src/client/northstar/operations/HistogramOperation.ts index e63de1632..7f48d1629 100644 --- a/src/client/northstar/operations/HistogramOperation.ts +++ b/src/client/northstar/operations/HistogramOperation.ts @@ -67,7 +67,7 @@ export class HistogramOperation extends BaseOperation implements IBaseFilterCons let brushes: string[] = []; this.BrushLinks.map(brushLink => { let brushHistogram = brushLink.b.GetT(KeyStore.Data, HistogramField); - if (brushHistogram && brushHistogram != FieldWaiting) { + if (brushHistogram && brushHistogram !== FieldWaiting) { let filterModels: FilterModel[] = []; brushes.push(FilterModel.GetFilterModelsRecursive(brushHistogram.Data, new Set(), filterModels, false)); } diff --git a/src/client/northstar/utils/ArrayUtil.ts b/src/client/northstar/utils/ArrayUtil.ts index f35c98317..a52ca6d96 100644 --- a/src/client/northstar/utils/ArrayUtil.ts +++ b/src/client/northstar/utils/ArrayUtil.ts @@ -7,14 +7,14 @@ export class ArrayUtil { return false; } let isComplex = typeof arr1[0] === "object"; - for (let i = 0; i < arr1.length; i++) { - if (isComplex && "Equals" in arr1[i]) { - if (arr1[i].Equals(arr2)) { + for (const ele of arr1) { + if (isComplex && "Equals" in ele) { + if (ele.Equals(arr2)) { return true; } } else { - if (arr1[i] === arr2) { + if (ele === arr2) { return true; } } @@ -63,9 +63,9 @@ export class ArrayUtil { public static Distinct(arr: any[]): any[] { let ret = []; - for (let i = 0; i < arr.length; i++) { - if (!ArrayUtil.Contains(ret, arr[i])) { - ret.push(arr[i]); + for (const ele of arr) { + if (!ArrayUtil.Contains(ret, ele)) { + ret.push(ele); } } return ret; diff --git a/src/client/northstar/utils/GeometryUtil.ts b/src/client/northstar/utils/GeometryUtil.ts index d5f3ba631..6d8acea20 100644 --- a/src/client/northstar/utils/GeometryUtil.ts +++ b/src/client/northstar/utils/GeometryUtil.ts @@ -85,7 +85,7 @@ export class GeometryUtil { // var xi = vs[i].x, yi = vs[i].y; // var xj = vs[j].x, yj = vs[j].y; - // var intersect = ((yi > y) != (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); + // var intersect = ((yi > y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); // if (intersect) // inside = !inside; // } diff --git a/src/client/northstar/utils/MathUtil.ts b/src/client/northstar/utils/MathUtil.ts index bb7e73871..7aa255096 100644 --- a/src/client/northstar/utils/MathUtil.ts +++ b/src/client/northstar/utils/MathUtil.ts @@ -93,7 +93,7 @@ export class MathUtil { public static DistToLineSegment(v: PIXIPoint, w: PIXIPoint, p: PIXIPoint) { // Return minimum distance between line segment vw and point p var l2 = MathUtil.DistSquared(v, w); // i.e. |w-v|^2 - avoid a sqrt - if (l2 == 0.0) return MathUtil.Dist(p, v); // v == w case + if (l2 === 0.0) return MathUtil.Dist(p, v); // v === w case // Consider the line extending the segment, parameterized as v + t (w - v). // We find projection of point p onto the line. // It falls where t = [(p-v) . (w-v)] / |w-v|^2 @@ -117,7 +117,7 @@ export class MathUtil { var b2 = ps2.x - pe2.x; var delta = a1 * b2 - a2 * b1; - if (delta == 0) { + if (delta === 0) { return undefined; } var c2 = a2 * ps2.x + b2 * ps2.y; @@ -147,19 +147,19 @@ export class MathUtil { var ret = new Array(); var dist = this.Dist(lineFrom, lineTo) var inter = this.LineSegmentIntersection(lineFrom, lineTo, r1, r2); - if (inter != null && this.PointInPIXIRectangle(inter, rect) && + if (inter && this.PointInPIXIRectangle(inter, rect) && this.Dist(inter, lineFrom) < dist && this.Dist(inter, lineTo) < dist) ret.push(inter); inter = this.LineSegmentIntersection(lineFrom, lineTo, r2, r3); - if (inter != null && this.PointInPIXIRectangle(inter, rect) && + if (inter && this.PointInPIXIRectangle(inter, rect) && this.Dist(inter, lineFrom) < dist && this.Dist(inter, lineTo) < dist) ret.push(inter); inter = this.LineSegmentIntersection(lineFrom, lineTo, r3, r4); - if (inter != null && this.PointInPIXIRectangle(inter, rect) && + if (inter && this.PointInPIXIRectangle(inter, rect) && this.Dist(inter, lineFrom) < dist && this.Dist(inter, lineTo) < dist) ret.push(inter); inter = this.LineSegmentIntersection(lineFrom, lineTo, r4, r1); - if (inter != null && this.PointInPIXIRectangle(inter, rect) && + if (inter && this.PointInPIXIRectangle(inter, rect) && this.Dist(inter, lineFrom) < dist && this.Dist(inter, lineTo) < dist) ret.push(inter); return ret; diff --git a/src/client/northstar/utils/SizeConverter.ts b/src/client/northstar/utils/SizeConverter.ts index bb91ed4a7..b5c4a16ab 100644 --- a/src/client/northstar/utils/SizeConverter.ts +++ b/src/client/northstar/utils/SizeConverter.ts @@ -54,7 +54,7 @@ export class SizeConverter { } 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 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]; @@ -85,7 +85,7 @@ export class SizeConverter { return flip ? (this.RenderDimension) - retY : retY; } public DataToScreenCoord(v: number, axis: number) { - if (axis == 0) + if (axis === 0) return this.DataToScreenX(v); return this.DataToScreenY(v); } diff --git a/src/client/northstar/utils/Utils.ts b/src/client/northstar/utils/Utils.ts index b35dce820..c96b4cbd9 100644 --- a/src/client/northstar/utils/Utils.ts +++ b/src/client/northstar/utils/Utils.ts @@ -27,17 +27,17 @@ export class Utils { public static isBaseBrushable(obj: Object): obj is IBaseBrushable { let typed = >obj; - return typed != null && typed.BrusherModels !== undefined; + return typed !== null && typed.BrusherModels !== undefined; } public static isBaseFilterProvider(obj: Object): obj is IBaseFilterProvider { let typed = obj; - return typed != null && typed.FilterModels !== undefined; + return typed !== null && typed.FilterModels !== undefined; } public static isBaseFilterConsumer(obj: Object): obj is IBaseFilterConsumer { let typed = obj; - return typed != null && typed.FilterOperand !== undefined; + return typed !== null && typed.FilterOperand !== undefined; } public static EncodeQueryData(data: any): string { @@ -63,9 +63,9 @@ export class Utils { public static GetQueryVariable(variable: string) { let query = window.location.search.substring(1); let vars = query.split("&"); - for (let i = 0; i < vars.length; i++) { - let pair = vars[i].split("="); - if (decodeURIComponent(pair[0]) == variable) { + for (const variable of vars) { + let pair = variable.split("="); + if (decodeURIComponent(pair[0]) === variable) { return decodeURIComponent(pair[1]); } } diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 11bf24505..1bb00a3fc 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -60,10 +60,10 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> if (text[0] === '#') { let command = text.slice(1, text.length); this._fieldKey = new Key(command) - // if (command == "Title" || command == "title") { + // if (command === "Title" || command === "title") { // this._fieldKey = KeyStore.Title; // } - // else if (command == "Width" || command == "width") { + // else if (command === "Width" || command === "width") { // this._fieldKey = KeyStore.Width; // } this._title = "changed" diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index 33759d38a..74f868c11 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -62,7 +62,7 @@ export class Main extends React.Component { @computed private get mainContainer(): Document | undefined { let doc = this.userDocument.GetT(KeyStore.ActiveWorkspace, Document); - return doc == FieldWaiting ? undefined : doc; + return doc === FieldWaiting ? undefined : doc; } private set mainContainer(doc: Document | undefined) { @@ -84,7 +84,7 @@ export class Main extends React.Component { configure({ enforceActions: "observed" }); if (window.location.pathname !== RouteStore.home) { let pathname = window.location.pathname.split("/"); - if (pathname.length > 1 && pathname[pathname.length - 2] == 'doc') { + if (pathname.length > 1 && pathname[pathname.length - 2] === 'doc') { CurrentUserUtils.MainDocId = pathname[pathname.length - 1]; } }; diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx index ee752a2ca..7a5ab6e3c 100644 --- a/src/client/views/collections/CollectionBaseView.tsx +++ b/src/client/views/collections/CollectionBaseView.tsx @@ -65,13 +65,13 @@ export class CollectionBaseView extends React.Component { createsCycle(documentToAdd: Document, containerDocument: Document): boolean { let data = documentToAdd.GetList(KeyStore.Data, []); - for (let i = 0; i < data.length; i++) { - if (this.createsCycle(data[i], containerDocument)) + for (const doc of data) { + if (this.createsCycle(doc, containerDocument)) return true; } let annots = documentToAdd.GetList(KeyStore.Annotations, []); - for (let i = 0; i < annots.length; i++) { - if (this.createsCycle(annots[i], containerDocument)) + for (const annot of annots) { + if (this.createsCycle(annot, containerDocument)) return true; } for (let containerProto: FieldValue = containerDocument; containerProto && containerProto !== FieldWaiting; containerProto = containerProto.GetPrototype()) { diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 1b0ad0bee..2380709d2 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -101,12 +101,12 @@ export class CollectionDockingView extends React.Component this.props.Document.GetText(KeyStore.Data, ""), () => { - if (!this._goldenLayout || this._ignoreStateChange != JSON.stringify(this._goldenLayout.toConfig())) { + if (!this._goldenLayout || this._ignoreStateChange !== JSON.stringify(this._goldenLayout.toConfig())) { setTimeout(() => this.setupGoldenLayout(), 1); } this._ignoreStateChange = ""; @@ -193,7 +193,7 @@ export class CollectionDockingView extends React.Component { var className = (e.target as any).className; - if ((className == "lm_title" || className == "lm_tab lm_active") && (e.ctrlKey || e.altKey)) { + if ((className === "lm_title" || className === "lm_tab lm_active") && (e.ctrlKey || e.altKey)) { e.stopPropagation(); e.preventDefault(); let docid = (e.target as any).DashDocId; @@ -209,7 +209,7 @@ export class CollectionDockingView extends React.Component { - if (tab.hasOwnProperty("contentItem") && tab.contentItem.config.type != "stack") { - if (tab.titleElement[0].textContent.indexOf("-waiting") != -1) { + if (tab.hasOwnProperty("contentItem") && tab.contentItem.config.type !== "stack") { + if (tab.titleElement[0].textContent.indexOf("-waiting") !== -1) { Server.GetField(tab.contentItem.config.props.documentId, action((f: Opt) => { - if (f != undefined && f instanceof Document) { + if (f !== undefined && f instanceof Document) { f.GetTAsync(KeyStore.Title, TextField, (tfield) => { - if (tfield != undefined) { + if (tfield !== undefined) { tab.titleElement[0].textContent = f.Title; } }) @@ -296,9 +296,9 @@ export class DockedFrameRenderer extends React.Component { Server.GetField(this.props.documentId, action((f: Opt) => this._document = f as Document)); } - private _nativeWidth = () => { return this._document!.GetNumber(KeyStore.NativeWidth, this._panelWidth); } - private _nativeHeight = () => { return this._document!.GetNumber(KeyStore.NativeHeight, this._panelHeight); } - private _contentScaling = () => { return this._panelWidth / (this._nativeWidth() ? this._nativeWidth() : this._panelWidth); } + private _nativeWidth = () => this._document!.GetNumber(KeyStore.NativeWidth, this._panelWidth) + private _nativeHeight = () => this._document!.GetNumber(KeyStore.NativeHeight, this._panelHeight) + private _contentScaling = () => this._panelWidth / (this._nativeWidth() ? this._nativeWidth() : this._panelWidth) ScreenToLocalTransform = () => { let { scale, translateX, translateY } = Utils.GetScreenTransform(this._mainCont.current!); diff --git a/src/client/views/collections/CollectionPDFView.tsx b/src/client/views/collections/CollectionPDFView.tsx index 14ed70b8c..1f2e71f6e 100644 --- a/src/client/views/collections/CollectionPDFView.tsx +++ b/src/client/views/collections/CollectionPDFView.tsx @@ -33,7 +33,7 @@ export class CollectionPDFView extends React.Component { } onContextMenu = (e: React.MouseEvent): void => { - if (!e.isPropagationStopped() && this.props.Document.Id != "mainDoc") { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 + if (!e.isPropagationStopped() && this.props.Document.Id !== "mainDoc") { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 ContextMenu.Instance.addItem({ description: "PDFOptions", event: () => { } }); } } diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index 9dade94f1..3817d5333 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -151,7 +151,7 @@ export class CollectionSchemaView extends CollectionViewBase { }), style: { background: rowInfo.index === this._selectedIndex ? "lightGray" : "white", - //color: rowInfo.index == this._selectedIndex ? "white" : "black" + //color: rowInfo.index === this._selectedIndex ? "white" : "black" } }; } diff --git a/src/client/views/collections/CollectionVideoView.tsx b/src/client/views/collections/CollectionVideoView.tsx index 3ab6db5ef..afadfeefb 100644 --- a/src/client/views/collections/CollectionVideoView.tsx +++ b/src/client/views/collections/CollectionVideoView.tsx @@ -61,7 +61,7 @@ export class CollectionVideoView extends React.Component { @action updateTimecode = () => { if (this._player) { - if ((this._player as any).AHackBecauseSomethingResetsTheVideoToZero != -1) { + if ((this._player as any).AHackBecauseSomethingResetsTheVideoToZero !== -1) { this._player.currentTime = (this._player as any).AHackBecauseSomethingResetsTheVideoToZero; (this._player as any).AHackBecauseSomethingResetsTheVideoToZero = -1; } else { @@ -103,7 +103,7 @@ export class CollectionVideoView extends React.Component { } onContextMenu = (e: React.MouseEvent): void => { - if (!e.isPropagationStopped() && this.props.Document.Id != "mainDoc") { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 + if (!e.isPropagationStopped() && this.props.Document.Id !== "mainDoc") { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 ContextMenu.Instance.addItem({ description: "VideoOptions", event: () => { } }); } } diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 5b4caf58d..1b0cfd57b 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -28,7 +28,7 @@ export class CollectionView extends React.Component { } onContextMenu = (e: React.MouseEvent): void => { - if (!e.isPropagationStopped() && this.props.Document.Id != CurrentUserUtils.MainDocId) { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 + if (!e.isPropagationStopped() && this.props.Document.Id !== CurrentUserUtils.MainDocId) { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 ContextMenu.Instance.addItem({ description: "Freeform", event: () => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Freeform) }) ContextMenu.Instance.addItem({ description: "Schema", event: () => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Schema) }) ContextMenu.Instance.addItem({ description: "Treeview", event: () => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Tree) }) diff --git a/src/client/views/collections/CollectionViewBase.tsx b/src/client/views/collections/CollectionViewBase.tsx index b4784ae9c..3af3c5d63 100644 --- a/src/client/views/collections/CollectionViewBase.tsx +++ b/src/client/views/collections/CollectionViewBase.tsx @@ -91,11 +91,11 @@ export class CollectionViewBase extends React.Component let sourceDoc: Document = de.data.linkSourceDocumentView.props.Document; if (sourceDoc) runInAction(() => { let srcTarg = sourceDoc.GetT(KeyStore.Prototype, Document) - if (srcTarg && srcTarg != FieldWaiting) { + if (srcTarg && srcTarg !== FieldWaiting) { let linkDocs = srcTarg.GetList(KeyStore.LinkedToDocs, [] as Document[]); linkDocs.map(linkDoc => { let targDoc = linkDoc.GetT(KeyStore.LinkedToDocs, Document); - if (targDoc && targDoc != FieldWaiting) { + if (targDoc && targDoc !== FieldWaiting) { let dropdoc = targDoc.MakeDelegate(); de.data.droppedDocuments.push(dropdoc); this.props.addDocument(dropdoc, false); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 19227f5e0..52e40d64a 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -176,8 +176,8 @@ export class CollectionFreeFormView extends CollectionViewBase { e.stopPropagation(); e.preventDefault(); } else { - // if (modes[e.deltaMode] == 'pixels') coefficient = 50; - // else if (modes[e.deltaMode] == 'lines') coefficient = 1000; // This should correspond to line-height?? + // if (modes[e.deltaMode] === 'pixels') coefficient = 50; + // else if (modes[e.deltaMode] === 'lines') coefficient = 1000; // This should correspond to line-height?? let transform = this.getTransform(); let deltaScale = (1 - (e.deltaY / coefficient)); diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 7022fd972..704db1d4a 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -48,7 +48,7 @@ export class MarqueeView extends React.Component @action onPointerDown = (e: React.PointerEvent): void => { - if (e.buttons == 1 && !e.altKey && !e.metaKey && this.props.container.props.active()) { + if (e.buttons === 1 && !e.altKey && !e.metaKey && this.props.container.props.active()) { this._downX = this._lastX = e.pageX; this._downY = this._lastY = e.pageY; this._used = false; @@ -63,7 +63,7 @@ export class MarqueeView extends React.Component this._lastX = e.pageX; this._lastY = e.pageY; if (!e.cancelBubble) { - if (!this._used && e.buttons == 1 && !e.altKey && !e.metaKey && + if (!this._used && e.buttons === 1 && !e.altKey && !e.metaKey && (Math.abs(this._lastX - this._downX) > MarqueeView.DRAG_THRESHOLD || Math.abs(this._lastY - this._downY) > MarqueeView.DRAG_THRESHOLD)) { this._visible = true; } @@ -99,15 +99,15 @@ export class MarqueeView extends React.Component @action marqueeCommand = (e: KeyboardEvent) => { - if (e.key == "Backspace" || e.key == "Delete") { + if (e.key === "Backspace" || e.key === "Delete") { this.marqueeSelect().map(d => this.props.removeDocument(d)); let ink = this.props.container.props.Document.GetT(KeyStore.Ink, InkField); - if (ink && ink != FieldWaiting) { + if (ink && ink !== FieldWaiting) { this.marqueeInkDelete(ink.Data); } this.cleanupInteractions(); } - if (e.key == "c") { + if (e.key === "c") { let bounds = this.Bounds; let selected = this.marqueeSelect().map(d => { this.props.removeDocument(d); @@ -118,7 +118,7 @@ export class MarqueeView extends React.Component return d; }); let ink = this.props.container.props.Document.GetT(KeyStore.Ink, InkField); - let inkData = ink && ink != FieldWaiting ? ink.Data : undefined; + let inkData = ink && ink !== FieldWaiting ? ink.Data : undefined; //setTimeout(() => { let newCollection = Documents.FreeformDocument(selected, { x: bounds.left, diff --git a/src/client/views/collections/collectionFreeForm/PreviewCursor.tsx b/src/client/views/collections/collectionFreeForm/PreviewCursor.tsx index 93c98f7b0..599461f85 100644 --- a/src/client/views/collections/collectionFreeForm/PreviewCursor.tsx +++ b/src/client/views/collections/collectionFreeForm/PreviewCursor.tsx @@ -33,7 +33,7 @@ export class PreviewCursor extends React.Component { @action onPointerDown = (e: React.PointerEvent) => { - if (e.button == 0 && this.props.container.props.active()) { + if (e.button === 0 && this.props.container.props.active()) { document.removeEventListener("keypress", this.onKeyPress, false); this._showOnUp = true; this.DownX = e.pageX; diff --git a/src/client/views/nodes/Annotation.tsx b/src/client/views/nodes/Annotation.tsx index a2c7be1a8..e4f17940c 100644 --- a/src/client/views/nodes/Annotation.tsx +++ b/src/client/views/nodes/Annotation.tsx @@ -4,13 +4,13 @@ import { observer } from "mobx-react" import { observable, action } from 'mobx'; import 'react-pdf/dist/Page/AnnotationLayer.css' -interface IProps{ +interface IProps { Span: HTMLSpanElement; - X: number; - Y: number; - Highlights: any[]; - Annotations: any[]; - CurrAnno: any[]; + X: number; + Y: number; + Highlights: any[]; + Annotations: any[]; + CurrAnno: any[]; } @@ -23,95 +23,95 @@ interface IProps{ */ @observer export class Annotation extends React.Component { - + /** * changes color of the span (highlighted section) */ - onColorChange = (e:React.PointerEvent) => { - if (e.currentTarget.innerHTML == "r"){ + onColorChange = (e: React.PointerEvent) => { + if (e.currentTarget.innerHTML === "r") { this.props.Span.style.backgroundColor = "rgba(255,0,0, 0.3)" - } else if (e.currentTarget.innerHTML == "b"){ + } else if (e.currentTarget.innerHTML === "b") { this.props.Span.style.backgroundColor = "rgba(0,255, 255, 0.3)" - } else if (e.currentTarget.innerHTML == "y"){ + } else if (e.currentTarget.innerHTML === "y") { this.props.Span.style.backgroundColor = "rgba(255,255,0, 0.3)" - } else if (e.currentTarget.innerHTML == "g"){ + } else if (e.currentTarget.innerHTML === "g") { this.props.Span.style.backgroundColor = "rgba(76, 175, 80, 0.3)" } - + } /** * removes the highlighted span. Supposed to remove Annotation too, but I don't know how to unmount this */ @action - onRemove = (e:any) => { - let index:number = -1; + onRemove = (e: any) => { + let index: number = -1; //finding the highlight in the highlight array this.props.Highlights.forEach((e) => { - for (let i = 0; i < e.spans.length; i++){ - if (e.spans[i] == this.props.Span){ - index = this.props.Highlights.indexOf(e); - this.props.Highlights.splice(index, 1); + for (const span of e.spans) { + if (span === this.props.Span) { + index = this.props.Highlights.indexOf(e); + this.props.Highlights.splice(index, 1); } } }) //removing from CurrAnno and Annotation array - this.props.Annotations.splice(index, 1); + this.props.Annotations.splice(index, 1); this.props.CurrAnno.pop() - + //removing span from div - if(this.props.Span.parentElement){ - let nodesArray = this.props.Span.parentElement.childNodes; + if (this.props.Span.parentElement) { + let nodesArray = this.props.Span.parentElement.childNodes; nodesArray.forEach((e) => { - if (e == this.props.Span){ - if (this.props.Span.parentElement){ + if (e === this.props.Span) { + if (this.props.Span.parentElement) { this.props.Highlights.forEach((item) => { - if (item == e){ - item.remove(); + if (item === e) { + item.remove(); } }) - e.remove(); + e.remove(); } } - }) + }) } - - + + } render() { return ( -
-
+
+
-
- - - - +
+ + + +
- +
-
-
- + ); } } \ No newline at end of file diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx index 0ce991485..1bd934c25 100644 --- a/src/client/views/nodes/AudioBox.tsx +++ b/src/client/views/nodes/AudioBox.tsx @@ -29,7 +29,7 @@ export class AudioBox extends React.Component { render() { let field = this.props.Document.Get(this.props.fieldKey) - let path = field == FieldWaiting ? "http://techslides.com/demos/samples/sample.mp3" : + let path = field === FieldWaiting ? "http://techslides.com/demos/samples/sample.mp3" : field instanceof AudioField ? field.Data.href : "http://techslides.com/demos/samples/sample.mp3"; return ( diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index 1c9155dce..34cc326aa 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -77,7 +77,7 @@ export class DocumentContentsView extends React.Component { @action onEnterKey = (e: React.KeyboardEvent): void => { - if (e.key == 'Enter') { + if (e.key === 'Enter') { if (this._keyInput && this._valueInput) { let doc = this.props.Document.GetT(KeyStore.Data, Document); - if (!doc || doc == FieldWaiting) { + if (!doc || doc === FieldWaiting) { return } let realDoc = doc; @@ -70,7 +70,7 @@ export class KeyValueBox extends React.Component { createTable = () => { let doc = this.props.Document.GetT(KeyStore.Data, Document); - if (!doc || doc == FieldWaiting) { + if (!doc || doc === FieldWaiting) { return Loading... } let realDoc = doc; diff --git a/src/client/views/nodes/LinkBox.tsx b/src/client/views/nodes/LinkBox.tsx index e81f8fec7..4791d6029 100644 --- a/src/client/views/nodes/LinkBox.tsx +++ b/src/client/views/nodes/LinkBox.tsx @@ -49,7 +49,7 @@ export class LinkBox extends React.Component { } else if (contextDoc instanceof Document) { this.props.pairedDoc.GetTAsync(KeyStore.Page, NumberField).then((pfield: any) => { contextDoc.GetTAsync(KeyStore.CurPage, NumberField).then((cfield: any) => { - if (pfield != cfield) + if (pfield !== cfield) contextDoc.SetNumber(KeyStore.CurPage, pfield.Data); let contextView = DocumentManager.Instance.getDocumentView(contextDoc); if (contextView) { diff --git a/src/client/views/nodes/LinkMenu.tsx b/src/client/views/nodes/LinkMenu.tsx index 5eeb40772..6c2d24630 100644 --- a/src/client/views/nodes/LinkMenu.tsx +++ b/src/client/views/nodes/LinkMenu.tsx @@ -24,7 +24,7 @@ export class LinkMenu extends React.Component { renderLinkItems(links: Document[], key: Key, type: string) { return links.map(link => { let doc = link.GetT(key, Document); - if (doc && doc != FieldWaiting) { + if (doc && doc !== FieldWaiting) { return this._editingLink = link)} type={type} /> } }) diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index b4590df34..a08b320e8 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -34,7 +34,7 @@ export class VideoBox extends React.Component { var nativeWidth = this.props.Document.GetNumber(KeyStore.NativeWidth, 0); var nativeHeight = this.props.Document.GetNumber(KeyStore.NativeHeight, 0); var newNativeHeight = nativeWidth * r.entry.height / r.entry.width; - if (!nativeHeight && newNativeHeight != nativeHeight && !isNaN(newNativeHeight)) { + if (!nativeHeight && newNativeHeight !== nativeHeight && !isNaN(newNativeHeight)) { this.props.Document.SetNumber(KeyStore.Height, newNativeHeight / nativeWidth * this.props.Document.GetNumber(KeyStore.Width, 0)); this.props.Document.SetNumber(KeyStore.NativeHeight, newNativeHeight); } diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 92e2fabd4..c1d389001 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -20,7 +20,7 @@ export class WebBox extends React.Component { render() { let field = this.props.Document.Get(this.props.fieldKey); - let path = field == FieldWaiting ? "https://image.flaticon.com/icons/svg/66/66163.svg" : + let path = field === FieldWaiting ? "https://image.flaticon.com/icons/svg/66/66163.svg" : field instanceof WebField ? field.Data.href : "https://crossorigin.me/" + "https://cs.brown.edu"; let content = this.html ? diff --git a/src/fields/AudioField.ts b/src/fields/AudioField.ts index 8864471ae..252a5b74e 100644 --- a/src/fields/AudioField.ts +++ b/src/fields/AudioField.ts @@ -4,7 +4,7 @@ import { Types } from "../server/Message"; export class AudioField extends BasicField { constructor(data: URL | undefined = undefined, id?: FieldId, save: boolean = true) { - super(data == undefined ? new URL("http://techslides.com/demos/samples/sample.mp3") : data, save, id); + super(data === undefined ? new URL("http://techslides.com/demos/samples/sample.mp3") : data, save, id); } toString(): string { diff --git a/src/fields/BasicField.ts b/src/fields/BasicField.ts index a92c4a236..3083a1937 100644 --- a/src/fields/BasicField.ts +++ b/src/fields/BasicField.ts @@ -46,7 +46,7 @@ export abstract class BasicField extends Field { @action TrySetValue(value: any): boolean { - if (typeof value == typeof this.data) { + if (typeof value === typeof this.data) { this.Data = value; return true; } diff --git a/src/fields/ImageField.ts b/src/fields/ImageField.ts index a9ece7d7b..ef616b2ad 100644 --- a/src/fields/ImageField.ts +++ b/src/fields/ImageField.ts @@ -4,7 +4,7 @@ import { Types } from "../server/Message"; export class ImageField extends BasicField { constructor(data: URL | undefined = undefined, id?: FieldId, save: boolean = true) { - super(data == undefined ? new URL("http://cs.brown.edu/~bcz/bob_fettucine.jpg") : data, save, id); + super(data === undefined ? new URL("http://cs.brown.edu/~bcz/bob_fettucine.jpg") : data, save, id); } toString(): string { diff --git a/src/fields/ListField.ts b/src/fields/ListField.ts index c4008bd12..815a3df73 100644 --- a/src/fields/ListField.ts +++ b/src/fields/ListField.ts @@ -26,7 +26,7 @@ export class ListField extends BasicField { } this.observeDisposer = observe(this.Data as IObservableArray, (change: IArrayChange | IArraySplice) => { this.updateProxies() - if (change.type == "splice") { + if (change.type === "splice") { UndoManager.AddEvent({ undo: () => this.Data.splice(change.index, change.addedCount, ...change.removed), redo: () => this.Data.splice(change.index, change.removedCount, ...change.added) @@ -57,8 +57,8 @@ export class ListField extends BasicField { } private arraysEqual(a: any[], b: any[]) { if (a === b) return true; - if (a == null || b == null) return false; - if (a.length != b.length) return false; + if (a === null || b === null) return false; + if (a.length !== b.length) return false; // If you don't care about the order of the elements inside // the array, you should sort both arrays here. @@ -79,9 +79,9 @@ export class ListField extends BasicField { var added = this.data.length < this._proxies.length; var deleted = this.data.length > this._proxies.length; for (let i = 0; i < dataids.length && added; i++) - added = proxies.indexOf(dataids[i]) != -1; + added = proxies.indexOf(dataids[i]) !== -1; for (let i = 0; i < this._proxies.length && deleted; i++) - deleted = dataids.indexOf(proxies[i]) != -1; + deleted = dataids.indexOf(proxies[i]) !== -1; this._processingServerUpdate = true; for (let i = 0; i < proxies.length && added; i++) { diff --git a/src/fields/PDFField.ts b/src/fields/PDFField.ts index b6625387e..436c1cf2b 100644 --- a/src/fields/PDFField.ts +++ b/src/fields/PDFField.ts @@ -7,7 +7,7 @@ import { Types } from "../server/Message"; export class PDFField extends BasicField { constructor(data: URL | undefined = undefined, id?: FieldId, save: boolean = true) { - super(data == undefined ? new URL("http://cs.brown.edu/~bcz/bob_fettucine.jpg") : data, save, id); + super(data === undefined ? new URL("http://cs.brown.edu/~bcz/bob_fettucine.jpg") : data, save, id); } toString(): string { diff --git a/src/fields/VideoField.ts b/src/fields/VideoField.ts index 626e4ec83..992cc1641 100644 --- a/src/fields/VideoField.ts +++ b/src/fields/VideoField.ts @@ -4,7 +4,7 @@ import { Types } from "../server/Message"; export class VideoField extends BasicField { constructor(data: URL | undefined = undefined, id?: FieldId, save: boolean = true) { - super(data == undefined ? new URL("http://techslides.com/demos/sample-videos/small.mp4") : data, save, id); + super(data === undefined ? new URL("http://techslides.com/demos/sample-videos/small.mp4") : data, save, id); } toString(): string { diff --git a/src/server/index.ts b/src/server/index.ts index ce8bbefe8..f60e6e293 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -143,7 +143,7 @@ addSecureRoute( Method.GET, (user, res, req) => { let detector = new mobileDetect(req.headers['user-agent'] || ""); - if (detector.mobile() != null) { + if (detector.mobile() !== null) { res.sendFile(path.join(__dirname, '../../deploy/mobile/image.html')); } else { res.sendFile(path.join(__dirname, '../../deploy/index.html')); -- cgit v1.2.3-70-g09d2 From 8667cfd95ffb5a78392a8bfb78e4600c5da2acaa Mon Sep 17 00:00:00 2001 From: bob Date: Fri, 5 Apr 2019 11:49:59 -0400 Subject: fixed histograms --- src/client/northstar/dash-nodes/HistogramBox.scss | 5 +- .../dash-nodes/HistogramBoxPrimitives.scss | 16 ++++- .../dash-nodes/HistogramBoxPrimitives.tsx | 81 +++++++++++----------- 3 files changed, 57 insertions(+), 45 deletions(-) (limited to 'src/client/northstar') diff --git a/src/client/northstar/dash-nodes/HistogramBox.scss b/src/client/northstar/dash-nodes/HistogramBox.scss index 94da36e29..e899cf15e 100644 --- a/src/client/northstar/dash-nodes/HistogramBox.scss +++ b/src/client/northstar/dash-nodes/HistogramBox.scss @@ -29,9 +29,10 @@ .histogrambox-yaxislabel-text { position:absolute; left:0; - transform-origin: left; + width: 1000px; + transform-origin: 10px 10px; transform: rotate(-90deg); - text-align: center; + text-align: left; font-size: 14; font-weight: bold; bottom: calc(50% - 25px); diff --git a/src/client/northstar/dash-nodes/HistogramBoxPrimitives.scss b/src/client/northstar/dash-nodes/HistogramBoxPrimitives.scss index ce9edd65e..26203612a 100644 --- a/src/client/northstar/dash-nodes/HistogramBoxPrimitives.scss +++ b/src/client/northstar/dash-nodes/HistogramBoxPrimitives.scss @@ -4,10 +4,11 @@ } .histogramboxprimitives-border { border: 3px; - border-style: solid; - border-color: white; pointer-events: none; position: absolute; + fill:"transparent"; + stroke: white; + stroke-width: 1px; } .histogramboxprimitives-bar { position: absolute; @@ -23,8 +24,19 @@ width: 100%; height: 100%; } +.histogramboxprimitives-svgContainer { + position: absolute; + top:0; + left:0; + width:100%; + height: 100%; +} .histogramboxprimitives-line { position: absolute; background: darkGray; + stroke: darkGray; + stroke-width: 1px; + width:100%; + height:100%; 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 index e9adb3ce5..0918bc0c4 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, reaction, runInAction, trace } from "mobx"; +import { computed, observable, reaction, runInAction, trace, action } from "mobx"; import { observer } from "mobx-react"; import { Utils as DashUtils } from '../../../Utils'; import { FilterModel } from "../../northstar/core/filter/FilterModel"; @@ -11,6 +11,9 @@ import { StyleConstants } from "../../northstar/utils/StyleContants"; import { HistogramBinPrimitiveCollection, HistogramBinPrimitive } from "./HistogramBinPrimitiveCollection"; import { HistogramBox } from "./HistogramBox"; import "./HistogramBoxPrimitives.scss"; +import { JSXElement } from "babel-types"; +import { Utils } from "../utils/Utils"; +import { all } from "bluebird"; export interface HistogramPrimitivesProps { HistoBox: HistogramBox; @@ -23,20 +26,19 @@ export class HistogramBoxPrimitives extends React.Component this.drawRect(bp.Rect, bp.BarAxis, undefined, "border")); } - @computed get binPrimitives() { + @computed get barPrimitives() { let histoResult = this.props.HistoBox.HistogramResult; if (!histoResult || !histoResult.bins || !this.props.HistoBox.VisualBinRanges.length) return (null); - trace(); let allBrushIndex = ModelHelpers.AllBrushIndex(histoResult); - return Object.keys(histoResult.bins).reduce((prims, key) => { + return Object.keys(histoResult.bins).reduce((prims: JSX.Element[], key: string) => { 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[]); + }, [] as JSX.Element[]) } componentDidMount() { @@ -44,39 +46,38 @@ export class HistogramBoxPrimitives extends React.Component bp.BrushIndex == allBrushIndex); - return !allBrushPrim ? () => { } : () => runInAction(() => { + let rawAllBrushPrim = ArrayUtil.FirstOrDefault(binPrimitives, bp => bp.BrushIndex == allBrushIndex); + if (!rawAllBrushPrim) + return () => { } + let allBrushPrim = rawAllBrushPrim; + return () => runInAction(() => { if (ArrayUtil.Contains(this.histoOp.FilterModels, filterModel)) { - this._selectedPrims.splice(this._selectedPrims.indexOf(allBrushPrim!), 1); + this._selectedPrims.splice(this._selectedPrims.indexOf(allBrushPrim), 1); this.histoOp.RemoveFilterModels([filterModel]); } else { - this._selectedPrims.push(allBrushPrim!); + this._selectedPrims.push(allBrushPrim); this.histoOp.AddFilterModels([filterModel]); } }) } private renderGridLinesAndLabels(axis: number) { + trace(); 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[]); + 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; @@ -86,10 +87,11 @@ export class HistogramBoxPrimitives extends React.Component); - return this.drawEntity(xFrom, yFrom, line); + let trans2Xpercent = `${(xFrom + width) / this.renderDimension * 100}%`; + let trans2Ypercent = `${(yFrom + height) / this.renderDimension * 100}%`; + let trans1Xpercent = `${xFrom / this.renderDimension * 100}%` + let trans1Ypercent = `${yFrom / this.renderDimension * 100}%` + return } drawRect(r: PIXIRectangle, barAxis: number, color: number | undefined, classExt: string, tapHandler: () => void = () => { }) { if (r.height < 0) { @@ -100,25 +102,22 @@ export class HistogramBoxPrimitives extends React.Component { 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); + let transXpercent = `${r.x / this.renderDimension * 100}%` + let transYpercent = `${r.y / this.renderDimension * 100}%` + let widthXpercent = `${r.width / this.renderDimension * 100}%`; + let heightYpercent = `${r.height / this.renderDimension * 100}%`; + return ( { if (e.button == 0) tapHandler() }} + x={transXpercent} width={`${widthXpercent}`} y={transYpercent} height={`${heightYpercent}`} fill={color ? `${LABColor.RGBtoHexString(color)}` : "transparent"} />); } render() { + trace(); return
{this.xaxislines} {this.yaxislines} - {this.binPrimitives} - {this.selectedPrimitives} + + {this.barPrimitives} + {this.selectedPrimitives} +
} } \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 1dd49a9659df6d4f449193eb7dbffeb56e5063b8 Mon Sep 17 00:00:00 2001 From: bob Date: Fri, 5 Apr 2019 15:19:23 -0400 Subject: cleaned up histogram render transform. fixed brushing --- src/client/northstar/dash-nodes/HistogramBox.tsx | 2 +- .../CollectionFreeFormLinksView.tsx | 55 ++++++++++++---------- 2 files changed, 31 insertions(+), 26 deletions(-) (limited to 'src/client/northstar') diff --git a/src/client/northstar/dash-nodes/HistogramBox.tsx b/src/client/northstar/dash-nodes/HistogramBox.tsx index 49ebe5ebc..dd6e09900 100644 --- a/src/client/northstar/dash-nodes/HistogramBox.tsx +++ b/src/client/northstar/dash-nodes/HistogramBox.tsx @@ -148,7 +148,7 @@ export class HistogramBox extends React.Component { return ( runInAction(() => { this.PanelWidth = r.entry.width; this.PanelHeight = r.entry.height })}> {({ measureRef }) => -
+
{labelY} diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx index 35fa6f99f..d4809ac1c 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx @@ -12,6 +12,7 @@ import "./CollectionFreeFormLinksView.scss"; import { CollectionFreeFormLinkView } from "./CollectionFreeFormLinkView"; import React = require("react"); import v5 = require("uuid/v5"); +import { find } from "async"; @observer export class CollectionFreeFormLinksView extends React.Component { @@ -22,40 +23,44 @@ export class CollectionFreeFormLinksView extends React.Component { 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++) { + for (let j = 0; 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, -1); let x2 = dstDoc.GetNumber(KeyStore.X, 0); let x2w = dstDoc.GetNumber(KeyStore.Width, -1); - if (x1w < 0 || x2w < 0) + if (x1w < 0 || x2w < 0 || i == j) continue; - 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 ? brush.GetList(KeyStore.BrushingDocs, [] as Document[]) : []; - return (bdocs.length == 0 || (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); + let dstTarg = dstDoc; + let srcTarg = srcDoc; + let findBrush = (field: ListField) => field.Data.findIndex(brush => { + let bdocs = brush ? brush.GetList(KeyStore.BrushingDocs, [] as Document[]) : []; + return (bdocs.length && ((bdocs[0] == dstTarg && bdocs[1] == srcTarg)) ? true : false) + }); + let brushAction = (field: ListField) => { + let found = findBrush(field); + if (found != -1) { + console.log("REMOVE BRUSH " + srcTarg.Title + " " + dstTarg.Title); + field.Data.splice(found, 1); + } + }; + if (Math.abs(x1 + x1w - x2) < 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); - brushAction = brushAction = (field: ListField) => (findBrush(field) == -1) && field.Data.push(linkDoc); + brushAction = brushAction = (field: ListField) => { + if (findBrush(field) == -1) { + console.log("ADD BRUSH " + srcTarg.Title + " " + dstTarg.Title); + (findBrush(field) == -1) && field.Data.push(linkDoc); } - dstTarg.GetOrCreateAsync(KeyStore.BrushingDocs, ListField, brushAction); - srcTarg.GetOrCreateAsync(KeyStore.BrushingDocs, ListField, brushAction); - } - ))) + }; + } + dstTarg.GetOrCreateAsync(KeyStore.BrushingDocs, ListField, brushAction); + srcTarg.GetOrCreateAsync(KeyStore.BrushingDocs, ListField, brushAction); + } } }) -- cgit v1.2.3-70-g09d2 From 3a9f6df918ad45e55b0c6a540cb566aff4940288 Mon Sep 17 00:00:00 2001 From: bob Date: Mon, 8 Apr 2019 12:49:39 -0400 Subject: added copyOnDrag stuff. --- src/client/documents/Documents.ts | 2 + src/client/northstar/dash-fields/HistogramField.ts | 2 +- .../northstar/operations/HistogramOperation.ts | 4 + src/client/util/DragManager.ts | 14 +-- src/client/views/Main.tsx | 64 +++++-------- .../views/collections/CollectionTreeView.tsx | 11 ++- .../views/collections/CollectionViewBase.tsx | 4 +- src/fields/Document.ts | 30 +++++- src/fields/KeyStore.ts | 105 ++++++++++++--------- 9 files changed, 133 insertions(+), 103 deletions(-) (limited to 'src/client/northstar') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 1f0744782..7d2f9cde1 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -43,6 +43,7 @@ export interface DocumentOptions { layoutKeys?: Key[]; viewType?: number; backgroundColor?: string; + copyDraggedItems?: boolean; } export namespace Documents { @@ -86,6 +87,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.copyDraggedItems !== undefined) { doc.SetBoolean(KeyStore.CopyDraggedItems, options.copyDraggedItems); } return doc; } diff --git a/src/client/northstar/dash-fields/HistogramField.ts b/src/client/northstar/dash-fields/HistogramField.ts index 90be70b80..48731f52d 100644 --- a/src/client/northstar/dash-fields/HistogramField.ts +++ b/src/client/northstar/dash-fields/HistogramField.ts @@ -27,7 +27,7 @@ export class HistogramField extends BasicField { } Copy(): Field { - return new HistogramField(this.Data); + return new HistogramField(this.Data.Copy()); } ToScriptString(): string { diff --git a/src/client/northstar/operations/HistogramOperation.ts b/src/client/northstar/operations/HistogramOperation.ts index e63de1632..840520235 100644 --- a/src/client/northstar/operations/HistogramOperation.ts +++ b/src/client/northstar/operations/HistogramOperation.ts @@ -42,6 +42,10 @@ export class HistogramOperation extends BaseOperation implements IBaseFilterCons this.SchemaName = schemaName; } + Copy(): HistogramOperation { + return new HistogramOperation(this.SchemaName, this.X, this.Y, this.V, this.Normalization); + } + Equals(other: Object): boolean { throw new Error("Method not implemented."); } diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 043932de5..c1919093e 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -10,7 +10,8 @@ import { DocumentView } from "../views/nodes/DocumentView"; export function setupDrag( _reference: React.RefObject, docFunc: () => Document, - removeFunc: (containingCollection: CollectionView) => void = () => { } + removeFunc: (containingCollection: CollectionView) => void = () => { }, + copyOnDrop: boolean = false ) { let onRowMove = action( (e: PointerEvent): void => { @@ -20,6 +21,7 @@ export function setupDrag( document.removeEventListener("pointermove", onRowMove); document.removeEventListener("pointerup", onRowUp); var dragData = new DragManager.DocumentDragData([docFunc()]); + dragData.copyOnDrop = copyOnDrop; dragData.removeDocument = removeFunc; DragManager.StartDocumentDrag([_reference.current!], dragData, e.x, e.y); } @@ -125,6 +127,7 @@ export namespace DragManager { xOffset?: number; yOffset?: number; aliasOnDrop?: boolean; + copyOnDrop?: boolean; removeDocument?: (collectionDrop: CollectionView) => void; [id: string]: any; } @@ -136,15 +139,12 @@ export namespace DragManager { downY: number, options?: DragOptions ) { - StartDrag( - eles, - dragData, - downX, downY, - options, + StartDrag(eles, dragData, downX, downY, options, (dropData: { [id: string]: any }) => (dropData.droppedDocuments = dragData.aliasOnDrop ? dragData.draggedDocuments.map(d => d.CreateAlias()) - : dragData.draggedDocuments) + : dragData.copyOnDrop ? dragData.draggedDocuments.map(d => d.Copy(true) as Document) : + dragData.draggedDocuments) ); } diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index 237eb3b6e..b4ab9e21d 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -1,57 +1,41 @@ -import { action, configure, observable, runInAction, trace, computed, reaction } from 'mobx'; +import { IconName, library } from '@fortawesome/fontawesome-svg-core'; +import { faFilePdf, faFilm, faFont, faGlobeAsia, faImage, faMusic, faObjectGroup, faPenNib, faRedoAlt, faTable, faTree, faUndoAlt } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { action, computed, configure, observable, runInAction } from 'mobx'; +import { observer } from 'mobx-react'; import "normalize.css"; import * as React from 'react'; import * as ReactDOM from 'react-dom'; +import Measure from 'react-measure'; +import * as request from 'request'; import { Document } from '../../fields/Document'; +import { Field, FieldWaiting, Opt } from '../../fields/Field'; import { KeyStore } from '../../fields/KeyStore'; -import "./Main.scss"; +import { ListField } from '../../fields/ListField'; +import { WorkspacesMenu } from '../../server/authentication/controllers/WorkspacesMenu'; +import { CurrentUserUtils } from '../../server/authentication/models/current_user_utils'; import { MessageStore } from '../../server/Message'; +import { RouteStore } from '../../server/RouteStore'; +import { ServerUtils } from '../../server/ServerUtil'; import { Utils } from '../../Utils'; -import * as request from 'request' -import * as rp from 'request-promise' import { Documents } from '../documents/Documents'; +import { ColumnAttributeModel } from '../northstar/core/attribute/AttributeModel'; +import { AttributeTransformationModel } from '../northstar/core/attribute/AttributeTransformationModel'; +import { Gateway, Settings } from '../northstar/manager/Gateway'; +import { AggregateFunction, Catalog } from '../northstar/model/idea/idea'; +import '../northstar/model/ModelExtensions'; +import { HistogramOperation } from '../northstar/operations/HistogramOperation'; +import '../northstar/utils/Extensions'; import { Server } from '../Server'; import { setupDrag } from '../util/DragManager'; import { Transform } from '../util/Transform'; -import { UndoManager, undoBatch } from '../util/UndoManager'; -import { WorkspacesMenu } from '../../server/authentication/controllers/WorkspacesMenu'; +import { UndoManager } from '../util/UndoManager'; import { CollectionDockingView } from './collections/CollectionDockingView'; import { ContextMenu } from './ContextMenu'; import { DocumentDecorations } from './DocumentDecorations'; -import { DocumentView } from './nodes/DocumentView'; -import "./Main.scss"; -import { observer } from 'mobx-react'; import { InkingControl } from './InkingControl'; -import { RouteStore } from '../../server/RouteStore'; -import { library, IconName } from '@fortawesome/fontawesome-svg-core'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { faFont } from '@fortawesome/free-solid-svg-icons'; -import { faImage } from '@fortawesome/free-solid-svg-icons'; -import { faFilePdf } from '@fortawesome/free-solid-svg-icons'; -import { faObjectGroup } from '@fortawesome/free-solid-svg-icons'; -import { faTable } from '@fortawesome/free-solid-svg-icons'; -import { faGlobeAsia } from '@fortawesome/free-solid-svg-icons'; -import { faUndoAlt } from '@fortawesome/free-solid-svg-icons'; -import { faRedoAlt } from '@fortawesome/free-solid-svg-icons'; -import { faPenNib } from '@fortawesome/free-solid-svg-icons'; -import { faFilm } from '@fortawesome/free-solid-svg-icons'; -import { faMusic } from '@fortawesome/free-solid-svg-icons'; -import { faTree } from '@fortawesome/free-solid-svg-icons'; -import Measure from 'react-measure'; -import { DashUserModel } from '../../server/authentication/models/user_model'; -import { ServerUtils } from '../../server/ServerUtil'; -import { CurrentUserUtils } from '../../server/authentication/models/current_user_utils'; -import { Field, Opt, FieldWaiting } from '../../fields/Field'; -import { ListField } from '../../fields/ListField'; -import { Gateway, Settings } from '../northstar/manager/Gateway'; -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'; -import { CollectionView } from './collections/CollectionView'; +import "./Main.scss"; +import { DocumentView } from './nodes/DocumentView'; @observer export class Main extends React.Component { @@ -247,7 +231,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._northstarSchemas, { width: 250, height: 400, title: "northstar schemas" })); + let addTreeNode = action(() => Documents.TreeDocument(this._northstarSchemas, { width: 250, height: 400, title: "northstar schemas", copyDraggedItems: true })); 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" })); diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 70790af18..0b12f11fd 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -18,6 +18,7 @@ import React = require("react") export interface TreeViewProps { document: Document; deleteDoc: (doc: Document) => void; + copyOnDrag: boolean; } export enum BulletType { @@ -63,7 +64,7 @@ class TreeView extends React.Component { */ renderTitle() { let reference = React.createRef(); - let onItemDown = setupDrag(reference, () => this.props.document, (containingCollection: CollectionView) => this.props.deleteDoc(this.props.document)); + let onItemDown = setupDrag(reference, () => this.props.document, (containingCollection: CollectionView) => this.props.deleteDoc(this.props.document), this.props.copyOnDrag); let editableView = (titleString: string) => ( { render() { let bulletType = BulletType.List; let childElements: JSX.Element | undefined = undefined; - var children = this.props.document.GetT>(KeyStore.Data, ListField); if (children && children !== FieldWaiting) { // add children for a collection if (!this._collapsed) { bulletType = BulletType.Collapsible; childElements =
    - {children.Data.map(value => )} + {children.Data.map(value => )}
} else bulletType = BulletType.Collapsed; @@ -118,10 +118,11 @@ export class CollectionTreeView extends CollectionViewBase { } render() { - var children = this.props.Document.GetT>(KeyStore.Data, ListField); + let children = this.props.Document.GetT>(KeyStore.Data, ListField); + let copyOnDrag = this.props.Document.GetBoolean(KeyStore.CopyDraggedItems, false); let childrenElement = !children || children === FieldWaiting ? (null) : (children.Data.map(value => - ) + ) ) return ( diff --git a/src/client/views/collections/CollectionViewBase.tsx b/src/client/views/collections/CollectionViewBase.tsx index 458bae7ab..7cf49e215 100644 --- a/src/client/views/collections/CollectionViewBase.tsx +++ b/src/client/views/collections/CollectionViewBase.tsx @@ -82,13 +82,13 @@ export class CollectionViewBase extends React.Component @action protected drop(e: Event, de: DragManager.DropEvent): boolean { if (de.data instanceof DragManager.DocumentDragData) { - if (de.data.aliasOnDrop) { + if (de.data.aliasOnDrop || de.data.copyOnDrop) { [KeyStore.Width, KeyStore.Height, KeyStore.CurPage].map(key => de.data.draggedDocuments.map((draggedDocument: Document, i: number) => draggedDocument.GetTAsync(key, NumberField, (f: Opt) => f ? de.data.droppedDocuments[i].SetNumber(key, f.Data) : null))); } let added = de.data.droppedDocuments.reduce((added, d) => this.props.addDocument(d, false), true); - if (added && de.data.removeDocument && !de.data.aliasOnDrop) { + if (added && de.data.removeDocument && !de.data.aliasOnDrop && !de.data.copyOnDrop) { de.data.removeDocument(this.props.CollectionView); } e.stopPropagation(); diff --git a/src/fields/Document.ts b/src/fields/Document.ts index 538d4ada9..02004678d 100644 --- a/src/fields/Document.ts +++ b/src/fields/Document.ts @@ -10,6 +10,9 @@ import { Types } from "../server/Message"; import { UndoManager } from "../client/util/UndoManager"; import { HtmlField } from "./HtmlField"; import { BooleanField } from "./BooleanField"; +import { allLimit } from "async"; +import { prototype } from "nodemailer/lib/smtp-pool"; +import { HistogramField } from "../client/northstar/dash-fields/HistogramField"; export class Document extends Field { //TODO tfs: We should probably store FieldWaiting in fields when we request it from the server so that we don't set up multiple server gets for the same document and field @@ -343,7 +346,10 @@ export class Document extends Field { SetText(key: Key, value: string, replaceWrongType = true) { this.SetData(key, value, TextField, replaceWrongType); } - + @action + SetBoolean(key: Key, value: boolean, replaceWrongType = true) { + this.SetData(key, value, BooleanField, replaceWrongType); + } @action SetNumber(key: Key, value: number, replaceWrongType = true) { this.SetData(key, value, NumberField, replaceWrongType); @@ -393,8 +399,26 @@ export class Document extends Field { return title; //throw new Error("Method not implemented."); } - Copy(): Field { - throw new Error("Method not implemented."); + Copy(copyProto?: boolean, id?: string): Field { + let copy = new Document(); + this._proxies.forEach((fieldid, keyid) => { // copy each prototype field + let key = KeyStore.KeyLookup(keyid); + if (key) { + this.GetAsync(key, (field: Opt) => { + if (key === KeyStore.Prototype && copyProto) { // handle prototype field specially + if (field instanceof Document) { + copy.Set(key, field.Copy(false)); // only copying one level of prototypes for now... + } + } + else + if (field instanceof Document) // ... TODO bcz: should we copy documents or reference them + copy.Set(key!, field) + else if (field) + copy.Set(key!, field.Copy()) + }) + } + }); + return copy; } ToJson(): { type: Types; data: [string, string][]; _id: string } { diff --git a/src/fields/KeyStore.ts b/src/fields/KeyStore.ts index 6ed3b1604..42dc34c51 100644 --- a/src/fields/KeyStore.ts +++ b/src/fields/KeyStore.ts @@ -2,49 +2,64 @@ import { Key } from "./Key"; import { KeyTransfer } from "../server/Message"; export namespace KeyStore { - export const Prototype = new Key("Prototype"); - export const X = new Key("X"); - export const Y = new Key("Y"); - export const Page = new Key("Page"); - export const Title = new Key("Title"); - export const Author = new Key("Author"); - export const PanX = new Key("PanX"); - export const PanY = new Key("PanY"); - export const Scale = new Key("Scale"); - export const NativeWidth = new Key("NativeWidth"); - export const NativeHeight = new Key("NativeHeight"); - export const Width = new Key("Width"); - export const Height = new Key("Height"); - export const ZIndex = new Key("ZIndex"); - export const Data = new Key("Data"); - export const Annotations = new Key("Annotations"); - export const ViewType = new Key("ViewType"); - export const Layout = new Key("Layout"); - export const BackgroundColor = new Key("BackgroundColor"); - export const BackgroundLayout = new Key("BackgroundLayout"); - export const OverlayLayout = new Key("OverlayLayout"); - export const LayoutKeys = new Key("LayoutKeys"); - export const LayoutFields = new Key("LayoutFields"); - export const ColumnsKey = new Key("SchemaColumns"); - export const SchemaSplitPercentage = new Key("SchemaSplitPercentage"); - 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"); - export const LinkTags = new Key("LinkTag"); - export const Thumbnail = new Key("Thumbnail"); - export const ThumbnailPage = new Key("ThumbnailPage"); - export const CurPage = new Key("CurPage"); - export const AnnotationOn = new Key("AnnotationOn"); - export const NumPages = new Key("NumPages"); - export const Ink = new Key("Ink"); - export const Cursors = new Key("Cursors"); - export const OptionalRightCollection = new Key("OptionalRightCollection"); - export const Archives = new Key("Archives"); - export const Updated = new Key("Updated"); - export const Workspaces = new Key("Workspaces"); - export const Minimized = new Key("Minimized"); + export const Prototype = new Key("Prototype"); + export const X = new Key("X"); + export const Y = new Key("Y"); + export const Page = new Key("Page"); + export const Title = new Key("Title"); + export const Author = new Key("Author"); + export const PanX = new Key("PanX"); + export const PanY = new Key("PanY"); + export const Scale = new Key("Scale"); + export const NativeWidth = new Key("NativeWidth"); + export const NativeHeight = new Key("NativeHeight"); + export const Width = new Key("Width"); + export const Height = new Key("Height"); + export const ZIndex = new Key("ZIndex"); + export const Data = new Key("Data"); + export const Annotations = new Key("Annotations"); + export const ViewType = new Key("ViewType"); + export const Layout = new Key("Layout"); + export const BackgroundColor = new Key("BackgroundColor"); + export const BackgroundLayout = new Key("BackgroundLayout"); + export const OverlayLayout = new Key("OverlayLayout"); + export const LayoutKeys = new Key("LayoutKeys"); + export const LayoutFields = new Key("LayoutFields"); + export const ColumnsKey = new Key("SchemaColumns"); + export const SchemaSplitPercentage = new Key("SchemaSplitPercentage"); + 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"); + export const LinkTags = new Key("LinkTag"); + export const Thumbnail = new Key("Thumbnail"); + export const ThumbnailPage = new Key("ThumbnailPage"); + export const CurPage = new Key("CurPage"); + export const AnnotationOn = new Key("AnnotationOn"); + export const NumPages = new Key("NumPages"); + export const Ink = new Key("Ink"); + export const Cursors = new Key("Cursors"); + export const OptionalRightCollection = new Key("OptionalRightCollection"); + export const Archives = new Key("Archives"); + export const Workspaces = new Key("Workspaces"); + export const Minimized = new Key("Minimized"); + export const CopyDraggedItems = new Key("CopyDraggedItems"); + + export const KeyList: Key[] = [Prototype, X, Y, Page, Title, Author, PanX, PanY, Scale, NativeWidth, NativeHeight, + Width, Height, ZIndex, Data, Annotations, ViewType, Layout, BackgroundColor, BackgroundLayout, OverlayLayout, LayoutKeys, + LayoutFields, ColumnsKey, SchemaSplitPercentage, Caption, ActiveWorkspace, DocumentText, BrushingDocs, LinkedToDocs, LinkedFromDocs, + LinkDescription, LinkTags, Thumbnail, ThumbnailPage, CurPage, AnnotationOn, NumPages, Ink, Cursors, OptionalRightCollection, + Archives, Workspaces, Minimized, CopyDraggedItems + ]; + export function KeyLookup(keyid: string) { + for (let i = 0; i < KeyList.length; i++) { + let keylistid = KeyList[i].Id; + if (keylistid === keyid) + return KeyList[i]; + } + return null; + } } -- cgit v1.2.3-70-g09d2 From 5e086920bf97297a02bcd38faea56454c2220279 Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Mon, 8 Apr 2019 22:45:22 -0400 Subject: Enabled semi-colon and braces linter rule --- src/Utils.ts | 12 +-- src/client/Server.ts | 35 ++++---- src/client/SocketStub.ts | 24 +++--- src/client/documents/Documents.ts | 38 +++++---- src/client/northstar/core/BaseObject.ts | 4 +- .../northstar/core/attribute/AttributeModel.ts | 6 +- .../core/attribute/AttributeTransformationModel.ts | 17 ++-- .../core/attribute/CalculatedAttributeModel.ts | 2 +- .../northstar/core/brusher/IBaseBrushable.ts | 4 +- src/client/northstar/core/brusher/IBaseBrusher.ts | 2 +- src/client/northstar/core/filter/FilterModel.ts | 2 +- .../northstar/core/filter/IBaseFilterConsumer.ts | 4 +- .../northstar/core/filter/IBaseFilterProvider.ts | 2 +- .../northstar/core/filter/ValueComparision.ts | 16 ++-- src/client/northstar/dash-fields/HistogramField.ts | 2 +- .../dash-nodes/HistogramBinPrimitiveCollection.ts | 12 +-- src/client/northstar/dash-nodes/HistogramBox.tsx | 24 +++--- .../dash-nodes/HistogramBoxPrimitives.tsx | 40 +++++---- .../dash-nodes/HistogramLabelPrimitives.tsx | 15 ++-- src/client/northstar/manager/Gateway.ts | 2 +- src/client/northstar/model/ModelExtensions.ts | 18 ++-- src/client/northstar/model/ModelHelpers.ts | 8 +- .../model/binRanges/AlphabeticVisualBinRange.ts | 4 +- .../model/binRanges/DateTimeVisualBinRange.ts | 4 +- .../model/binRanges/NominalVisualBinRange.ts | 4 +- .../model/binRanges/QuantitativeVisualBinRange.ts | 2 +- .../northstar/model/binRanges/VisualBinRange.ts | 2 +- .../model/binRanges/VisualBinRangeHelper.ts | 14 +-- src/client/northstar/operations/BaseOperation.ts | 9 +- .../northstar/operations/HistogramOperation.ts | 2 +- src/client/northstar/utils/ArrayUtil.ts | 2 +- src/client/northstar/utils/Extensions.ts | 6 +- src/client/northstar/utils/GeometryUtil.ts | 34 ++++---- src/client/northstar/utils/MathUtil.ts | 38 +++++---- src/client/northstar/utils/SizeConverter.ts | 16 ++-- src/client/northstar/utils/StyleContants.ts | 2 +- src/client/northstar/utils/Utils.ts | 8 +- src/client/util/DocumentManager.ts | 12 +-- src/client/util/DragManager.ts | 5 +- src/client/util/RichTextSchema.tsx | 42 ++++----- src/client/util/Scripting.ts | 10 +-- src/client/util/ScrollBox.tsx | 4 +- src/client/util/SelectionManager.ts | 4 +- src/client/util/TooltipTextMenu.tsx | 38 ++++----- src/client/util/Transform.ts | 20 ++--- src/client/util/TypedEvent.ts | 2 +- src/client/util/UndoManager.ts | 24 +++--- src/client/views/ContextMenu.tsx | 14 +-- src/client/views/ContextMenuItem.tsx | 4 +- src/client/views/DocumentDecorations.tsx | 99 +++++++++++----------- src/client/views/EditableView.tsx | 10 +-- src/client/views/InkingCanvas.tsx | 15 ++-- src/client/views/InkingControl.tsx | 12 +-- src/client/views/InkingStroke.tsx | 6 +- src/client/views/Main.tsx | 55 ++++++------ .../views/collections/CollectionBaseView.tsx | 34 +++++--- .../views/collections/CollectionDockingView.tsx | 37 ++++---- src/client/views/collections/CollectionPDFView.tsx | 6 +- .../views/collections/CollectionSchemaView.tsx | 39 ++++----- src/client/views/collections/CollectionSubView.tsx | 41 ++++----- .../views/collections/CollectionTreeView.tsx | 14 +-- .../views/collections/CollectionVideoView.tsx | 6 +- src/client/views/collections/CollectionView.tsx | 20 ++--- .../CollectionFreeFormLinkView.tsx | 2 +- .../CollectionFreeFormLinksView.tsx | 18 ++-- .../CollectionFreeFormRemoteCursors.tsx | 6 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 33 ++++---- .../collections/collectionFreeForm/MarqueeView.tsx | 15 ++-- .../collectionFreeForm/PreviewCursor.tsx | 5 +- src/client/views/nodes/Annotation.tsx | 22 ++--- src/client/views/nodes/AudioBox.tsx | 12 +-- .../views/nodes/CollectionFreeFormDocumentView.tsx | 12 +-- src/client/views/nodes/DocumentContentsView.tsx | 6 +- src/client/views/nodes/DocumentView.tsx | 35 ++++---- src/client/views/nodes/FieldView.tsx | 29 ++++--- src/client/views/nodes/FormattedTextBox.tsx | 17 ++-- src/client/views/nodes/ImageBox.tsx | 12 +-- src/client/views/nodes/KeyValueBox.tsx | 18 ++-- src/client/views/nodes/KeyValuePair.tsx | 14 +-- src/client/views/nodes/LinkBox.tsx | 17 ++-- src/client/views/nodes/LinkEditor.tsx | 6 +- src/client/views/nodes/LinkMenu.tsx | 10 +-- src/client/views/nodes/PDFBox.tsx | 56 ++++++------ src/client/views/nodes/Sticky.tsx | 6 +- src/client/views/nodes/VideoBox.tsx | 10 +-- src/client/views/nodes/WebBox.tsx | 6 +- src/debug/Test.tsx | 8 +- src/debug/Viewer.tsx | 48 +++++------ src/fields/AudioField.ts | 2 +- src/fields/BasicField.ts | 6 +- src/fields/Document.ts | 25 +++--- src/fields/DocumentReference.ts | 2 +- src/fields/Field.ts | 2 +- src/fields/HtmlField.ts | 2 +- src/fields/ImageField.ts | 2 +- src/fields/InkField.ts | 2 +- src/fields/Key.ts | 6 +- src/fields/KeyStore.ts | 3 +- src/fields/ListField.ts | 31 ++++--- src/fields/NumberField.ts | 4 +- src/fields/PDFField.ts | 4 +- src/fields/RichTextField.ts | 2 +- src/fields/TextField.ts | 4 +- src/fields/TupleField.ts | 6 +- src/fields/VideoField.ts | 2 +- src/fields/WebField.ts | 2 +- src/mobile/ImageUpload.tsx | 14 +-- src/server/Client.ts | 4 +- src/server/authentication/config/passport.ts | 6 +- .../authentication/controllers/WorkspacesMenu.tsx | 2 +- .../authentication/controllers/user_controller.ts | 20 ++--- .../authentication/models/current_user_utils.ts | 8 +- src/server/authentication/models/user_model.ts | 2 +- src/server/database.ts | 34 ++++---- src/server/index.ts | 76 ++++++++--------- test/test.ts | 6 +- tslint.json | 16 ++-- 117 files changed, 901 insertions(+), 826 deletions(-) (limited to 'src/client/northstar') diff --git a/src/Utils.ts b/src/Utils.ts index 8bd7f2f5c..b0e66787e 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -6,16 +6,16 @@ import { Message, Types } from './server/Message'; export class Utils { public static GenerateGuid(): string { - return v4() + return v4(); } public static GenerateDeterministicGuid(seed: string): string { - return v5(seed, v5.URL) + return v5(seed, v5.URL); } public static GetScreenTransform(ele: HTMLElement): { scale: number, translateX: number, translateY: number } { if (!ele) { - return { scale: 1, translateX: 1, translateY: 1 } + return { scale: 1, translateX: 1, translateY: 1 }; } const rect = ele.getBoundingClientRect(); const scale = ele.offsetWidth === 0 && rect.width === 0 ? 1 : rect.width / ele.offsetWidth; @@ -55,8 +55,8 @@ export class Utils { return (args: any) => { this.log(prefix, messageName, args, true); func(args); - } - }; + }; + } public static Emit(socket: Socket | SocketIOClient.Socket, message: Message, args: T) { this.log("Emit", message.Name, args, false); @@ -81,7 +81,7 @@ export class Utils { public static AddServerHandlerCallback(socket: Socket, message: Message, handler: (args: [T, (res: any) => any]) => any) { socket.on(message.Message, (arg: T, fn: (res: any) => any) => { this.log('S receiving', message.Name, arg, true); - handler([arg, this.loggingCallback('S sending', fn, message.Name)]) + handler([arg, this.loggingCallback('S sending', fn, message.Name)]); }); } } diff --git a/src/client/Server.ts b/src/client/Server.ts index 45c7144ca..857101a33 100644 --- a/src/client/Server.ts +++ b/src/client/Server.ts @@ -1,7 +1,7 @@ -import { Key } from "../fields/Key" +import { Key } from "../fields/Key"; import { ObservableMap, action, reaction } from "mobx"; -import { Field, FieldWaiting, FIELD_WAITING, Opt, FieldId } from "../fields/Field" -import { Document } from "../fields/Document" +import { Field, FieldWaiting, FIELD_WAITING, Opt, FieldId } from "../fields/Field"; +import { Document } from "../fields/Document"; import { SocketStub, FieldMap } from "./SocketStub"; import * as OpenSocket from 'socket.io-client'; import { Utils } from "./../Utils"; @@ -10,7 +10,7 @@ import { MessageStore, Types } from "./../server/Message"; export class Server { public static ClientFieldsCached: ObservableMap = new ObservableMap(); static Socket: SocketIOClient.Socket = OpenSocket(`${window.location.protocol}//${window.location.hostname}:4321`); - static GUID: string = Utils.GenerateGuid() + static GUID: string = Utils.GenerateGuid(); // Retrieves the cached value of the field and sends a request to the server for the real value (if it's not cached). @@ -25,15 +25,16 @@ export class Server { this.ClientFieldsCached.set(fieldid, FieldWaiting); SocketStub.SEND_FIELD_REQUEST(fieldid, action((field: Field | undefined) => { let cached = this.ClientFieldsCached.get(fieldid); - if (cached !== FieldWaiting) + if (cached !== FieldWaiting) { cb(cached); + } else { if (field) { this.ClientFieldsCached.set(fieldid, field); } else { - this.ClientFieldsCached.delete(fieldid) + this.ClientFieldsCached.delete(fieldid); } - cb(field) + cb(field); } })); } else if (cached !== FieldWaiting) { @@ -42,12 +43,12 @@ export class Server { reaction(() => this.ClientFieldsCached.get(fieldid), (field, reaction) => { if (field !== FieldWaiting) { - reaction.dispose() - cb(field) + reaction.dispose(); + cb(field); } - }) + }); } - } + }; if (callback) { fn(callback); } else { @@ -79,15 +80,15 @@ export class Server { let field = fields[id]; if (field) { if (!(this.ClientFieldsCached.get(field.Id) instanceof Field)) { - this.ClientFieldsCached.set(field.Id, field) + this.ClientFieldsCached.set(field.Id, field); } else { - throw new Error("we shouldn't be trying to replace things that are already in the cache") + throw new Error("we shouldn't be trying to replace things that are already in the cache"); } } else { if (this.ClientFieldsCached.get(id) === FieldWaiting) { this.ClientFieldsCached.delete(id); } else { - throw new Error("we shouldn't be trying to replace things that are already in the cache") + throw new Error("we shouldn't be trying to replace things that are already in the cache"); } } } @@ -99,9 +100,9 @@ export class Server { let realField = field as Field; existingFields[realField.Id] = realField; } - cb({ ...fields, ...existingFields }) + cb({ ...fields, ...existingFields }); } - }, { fireImmediately: true }) + }, { fireImmediately: true }); })); }; if (callback) { @@ -139,7 +140,7 @@ export class Server { public static UpdateField(field: Field) { if (!this.ClientFieldsCached.has(field.Id)) { - this.ClientFieldsCached.set(field.Id, field) + this.ClientFieldsCached.set(field.Id, field); } SocketStub.SEND_SET_FIELD(field); } diff --git a/src/client/SocketStub.ts b/src/client/SocketStub.ts index c3cd8bee6..257973e3d 100644 --- a/src/client/SocketStub.ts +++ b/src/client/SocketStub.ts @@ -1,7 +1,7 @@ -import { Key } from "../fields/Key" -import { Field, FieldId, Opt } from "../fields/Field" +import { Key } from "../fields/Key"; +import { Field, FieldId, Opt } from "../fields/Field"; import { ObservableMap } from "mobx"; -import { Document } from "../fields/Document" +import { Document } from "../fields/Document"; import { MessageStore, DocumentTransfer } from "../server/Message"; import { Utils } from "../Utils"; import { Server } from "./Server"; @@ -37,7 +37,7 @@ export class SocketStub { // document.fields.forEach((f, key) => (this.FieldStore.get(document.Id) as Document)._proxies.set(key.Id, (f as Field).Id)); console.log("sending " + document.Title); - Utils.Emit(Server.Socket, MessageStore.AddDocument, new DocumentTransfer(document.ToJson())) + Utils.Emit(Server.Socket, MessageStore.AddDocument, new DocumentTransfer(document.ToJson())); } public static SEND_FIELD_REQUEST(fieldid: FieldId): Promise>; @@ -50,12 +50,12 @@ export class SocketStub { } else { cb(undefined); } - }) - } + }); + }; if (callback) { fn(callback); } else { - return new Promise(fn) + return new Promise(fn); } } @@ -65,7 +65,7 @@ export class SocketStub { for (let field of fields) { fieldMap[field._id] = ServerUtils.FromJson(field); } - callback(fieldMap) + callback(fieldMap); }); } @@ -78,8 +78,9 @@ export class SocketStub { // server updates its document to hold a proxy mapping from key => fieldId var document = this.FieldStore.get(doc.Id) as Document; - if (document) + if (document) { document._proxies.set(key.Id, value.Id); + } // server adds the field to its repository of fields this.FieldStore.set(value.Id, value); @@ -93,8 +94,9 @@ export class SocketStub { // Server removes the field id from the document's list of field proxies var document = this.FieldStore.get(doc.Id) as Document; - if (document) + if (document) { document._proxies.delete(key.Id); + } } public static SEND_SET_FIELD(field: Field) { @@ -103,6 +105,6 @@ export class SocketStub { // ...SOCKET(SET_FIELD, field id, serialized field value) // Server updates the value of the field in its fieldstore - Utils.Emit(Server.Socket, MessageStore.SetField, field.ToJson()) + Utils.Emit(Server.Socket, MessageStore.SetField, field.ToJson()); } } diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 613b94abd..72e6e57ab 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -64,7 +64,7 @@ export namespace Documents { const webProtoId = "webProto"; const collProtoId = "collectionProto"; const kvpProtoId = "kvpProto"; - const videoProtoId = "videoProto" + const videoProtoId = "videoProto"; const audioProtoId = "audioProto"; export function initProtos(): Promise { @@ -102,7 +102,7 @@ export namespace Documents { if (options.height !== undefined) { doc.SetNumber(KeyStore.Height, options.height); } if (options.panx !== undefined) { doc.SetNumber(KeyStore.PanX, options.panx); } if (options.pany !== undefined) { doc.SetNumber(KeyStore.PanY, options.pany); } - return doc + return doc; } function setupPrototypeOptions(protoId: string, title: string, layout: string, options: DocumentOptions): Document { @@ -110,10 +110,12 @@ export namespace Documents { } function SetInstanceOptions(doc: Document, options: DocumentOptions, value: [T, { new(): U }] | Document, id?: string) { var deleg = doc.MakeDelegate(id); - if (value instanceof Document) - deleg.Set(KeyStore.Data, value) - else + if (value instanceof Document) { + deleg.Set(KeyStore.Data, value); + } + else { deleg.SetData(KeyStore.Data, value[0], value[1]); + } return assignOptions(deleg, options); } @@ -134,7 +136,7 @@ export namespace Documents { function CreateTextPrototype(): Document { let textProto = setupPrototypeOptions(textProtoId, "TEXT_PROTO", FormattedTextBox.LayoutString(), { x: 0, y: 0, width: 300, height: 150, layoutKeys: [KeyStore.Data] }); - return textProto + return textProto; } function CreatePdfPrototype(): Document { let pdfProto = setupPrototypeOptions(pdfProtoId, "PDF_PROTO", CollectionPDFView.LayoutString("AnnotationsKey"), @@ -168,7 +170,7 @@ export namespace Documents { } function CreateAudioPrototype(): Document { let audioProto = setupPrototypeOptions(audioProtoId, "AUDIO_PROTO", AudioBox.LayoutString(), - { x: 0, y: 0, width: 300, height: 150, layoutKeys: [KeyStore.Data] }) + { x: 0, y: 0, width: 300, height: 150, layoutKeys: [KeyStore.Data] }); return audioProto; } @@ -205,22 +207,22 @@ export namespace Documents { return assignToDelegate(SetInstanceOptions(webProto, options, [html, HtmlField]).MakeDelegate(), options); } export function KVPDocument(document: Document, options: DocumentOptions = {}, id?: string) { - return assignToDelegate(SetInstanceOptions(kvpProto, options, document, id), options) + return assignToDelegate(SetInstanceOptions(kvpProto, options, document, id), options); } export function FreeformDocument(documents: Array, options: DocumentOptions, id?: string, makePrototype: boolean = true) { if (!makePrototype) { - return SetInstanceOptions(collProto, { ...options, viewType: CollectionViewType.Freeform }, [documents, ListField], id) + return SetInstanceOptions(collProto, { ...options, viewType: CollectionViewType.Freeform }, [documents, ListField], id); } - return assignToDelegate(SetInstanceOptions(collProto, { ...options, viewType: CollectionViewType.Freeform }, [documents, ListField], id).MakeDelegate(), options) + return assignToDelegate(SetInstanceOptions(collProto, { ...options, viewType: CollectionViewType.Freeform }, [documents, ListField], id).MakeDelegate(), options); } export function SchemaDocument(documents: Array, options: DocumentOptions, id?: string) { - return assignToDelegate(SetInstanceOptions(collProto, { ...options, viewType: CollectionViewType.Schema }, [documents, ListField], id), options) + return assignToDelegate(SetInstanceOptions(collProto, { ...options, viewType: CollectionViewType.Schema }, [documents, ListField], id), options); } export function TreeDocument(documents: Array, options: DocumentOptions, id?: string) { - return assignToDelegate(SetInstanceOptions(collProto, { ...options, viewType: CollectionViewType.Tree }, [documents, ListField], id), options) + return assignToDelegate(SetInstanceOptions(collProto, { ...options, viewType: CollectionViewType.Tree }, [documents, ListField], id), options); } export function DockDocument(config: string, options: DocumentOptions, id?: string) { - return assignToDelegate(SetInstanceOptions(collProto, { ...options, viewType: CollectionViewType.Docking }, [config, TextField], id), options) + return assignToDelegate(SetInstanceOptions(collProto, { ...options, viewType: CollectionViewType.Docking }, [config, TextField], id), options); } export function CaptionDocument(doc: Document) { @@ -240,13 +242,13 @@ export namespace Documents {
` + FormattedTextBox.LayoutString("CaptionKey") + `
-
` }; +
`; } export function FixedCaption(fieldName: string = "Caption") { return `
` + FormattedTextBox.LayoutString(fieldName + "Key") + `
-
` }; +
`; } function OuterCaption() { return (` @@ -258,7 +260,7 @@ export namespace Documents {
- `) + `); } function InnerCaption() { return (` @@ -270,7 +272,7 @@ export namespace Documents {
- `) + `); } /* @@ -293,6 +295,6 @@ export namespace Documents {
- `) + `); } } \ No newline at end of file diff --git a/src/client/northstar/core/BaseObject.ts b/src/client/northstar/core/BaseObject.ts index f1761e643..ed3818071 100644 --- a/src/client/northstar/core/BaseObject.ts +++ b/src/client/northstar/core/BaseObject.ts @@ -1,5 +1,5 @@ -import { IEquatable } from '../utils/IEquatable' -import { IDisposable } from '../utils/IDisposable' +import { IEquatable } from '../utils/IEquatable'; +import { IDisposable } from '../utils/IDisposable'; export class BaseObject implements IEquatable, IDisposable { diff --git a/src/client/northstar/core/attribute/AttributeModel.ts b/src/client/northstar/core/attribute/AttributeModel.ts index 230bfecc8..c89b1617c 100644 --- a/src/client/northstar/core/attribute/AttributeModel.ts +++ b/src/client/northstar/core/attribute/AttributeModel.ts @@ -1,5 +1,5 @@ -import { Attribute, DataType, VisualizationHint } from '../../model/idea/idea' -import { BaseObject } from '../BaseObject' +import { Attribute, DataType, VisualizationHint } from '../../model/idea/idea'; +import { BaseObject } from '../BaseObject'; import { observable } from "mobx"; export abstract class AttributeModel extends BaseObject { @@ -93,7 +93,7 @@ export class BackendAttributeModel extends AttributeModel { } public get DisplayName(): string { - return this._displayName.ReplaceAll("_", " ");; + return this._displayName.ReplaceAll("_", " "); } public get CodeName(): string { diff --git a/src/client/northstar/core/attribute/AttributeTransformationModel.ts b/src/client/northstar/core/attribute/AttributeTransformationModel.ts index f50b78d51..66485183b 100644 --- a/src/client/northstar/core/attribute/AttributeTransformationModel.ts +++ b/src/client/northstar/core/attribute/AttributeTransformationModel.ts @@ -1,4 +1,4 @@ -; + import { computed, observable } from "mobx"; import { AggregateFunction } from "../../model/idea/idea"; import { AttributeModel } from "./AttributeModel"; @@ -20,16 +20,21 @@ export class AttributeTransformationModel implements IEquatable { if (this.AggregateFunction === AggregateFunction.Count) { return "count"; } - if (this.AggregateFunction === AggregateFunction.Avg) + if (this.AggregateFunction === AggregateFunction.Avg) { displayName = "avg(" + displayName + ")"; - else if (this.AggregateFunction === AggregateFunction.Max) + } + else if (this.AggregateFunction === AggregateFunction.Max) { displayName = "max(" + displayName + ")"; - else if (this.AggregateFunction === AggregateFunction.Min) + } + else if (this.AggregateFunction === AggregateFunction.Min) { displayName = "min(" + displayName + ")"; - else if (this.AggregateFunction === AggregateFunction.Sum) + } + else if (this.AggregateFunction === AggregateFunction.Sum) { displayName = "sum(" + displayName + ")"; - else if (this.AggregateFunction === AggregateFunction.SumE) + } + else if (this.AggregateFunction === AggregateFunction.SumE) { displayName = "sumE(" + displayName + ")"; + } return displayName; } diff --git a/src/client/northstar/core/attribute/CalculatedAttributeModel.ts b/src/client/northstar/core/attribute/CalculatedAttributeModel.ts index 0b8e0d12c..a197c1305 100644 --- a/src/client/northstar/core/attribute/CalculatedAttributeModel.ts +++ b/src/client/northstar/core/attribute/CalculatedAttributeModel.ts @@ -1,5 +1,5 @@ import { BackendAttributeModel, AttributeModel, CodeAttributeModel } from "./AttributeModel"; -import { DataType, VisualizationHint } from '../../model/idea/idea' +import { DataType, VisualizationHint } from '../../model/idea/idea'; export class CalculatedAttributeManager { public static AllCalculatedAttributes: Array = new Array(); diff --git a/src/client/northstar/core/brusher/IBaseBrushable.ts b/src/client/northstar/core/brusher/IBaseBrushable.ts index 99a36636f..c46db4d22 100644 --- a/src/client/northstar/core/brusher/IBaseBrushable.ts +++ b/src/client/northstar/core/brusher/IBaseBrushable.ts @@ -1,6 +1,6 @@ -import { PIXIPoint } from '../../utils/MathUtil' +import { PIXIPoint } from '../../utils/MathUtil'; import { IEquatable } from '../../utils/IEquatable'; -import { Document } from '../../../../fields/Document' +import { Document } from '../../../../fields/Document'; export interface IBaseBrushable extends IEquatable { BrusherModels: Array; diff --git a/src/client/northstar/core/brusher/IBaseBrusher.ts b/src/client/northstar/core/brusher/IBaseBrusher.ts index d7ae65464..d2de6ed62 100644 --- a/src/client/northstar/core/brusher/IBaseBrusher.ts +++ b/src/client/northstar/core/brusher/IBaseBrusher.ts @@ -1,4 +1,4 @@ -import { PIXIPoint } from '../../utils/MathUtil' +import { PIXIPoint } from '../../utils/MathUtil'; import { IEquatable } from '../../utils/IEquatable'; diff --git a/src/client/northstar/core/filter/FilterModel.ts b/src/client/northstar/core/filter/FilterModel.ts index 20fca77f5..e2ba3f652 100644 --- a/src/client/northstar/core/filter/FilterModel.ts +++ b/src/client/northstar/core/filter/FilterModel.ts @@ -15,7 +15,7 @@ export class FilterModel { public Equals(other: FilterModel): boolean { if (!Utils.EqualityHelper(this, other)) return false; - if (!this.isSame(this.ValueComparisons, (other as FilterModel).ValueComparisons)) return false; + if (!this.isSame(this.ValueComparisons, (other).ValueComparisons)) return false; return true; } diff --git a/src/client/northstar/core/filter/IBaseFilterConsumer.ts b/src/client/northstar/core/filter/IBaseFilterConsumer.ts index 93f66a154..59d7adf4c 100644 --- a/src/client/northstar/core/filter/IBaseFilterConsumer.ts +++ b/src/client/northstar/core/filter/IBaseFilterConsumer.ts @@ -1,5 +1,5 @@ -import { FilterOperand } from '../filter/FilterOperand' -import { IEquatable } from '../../utils/IEquatable' +import { FilterOperand } from '../filter/FilterOperand'; +import { IEquatable } from '../../utils/IEquatable'; import { Document } from "../../../../fields/Document"; export interface IBaseFilterConsumer extends IEquatable { diff --git a/src/client/northstar/core/filter/IBaseFilterProvider.ts b/src/client/northstar/core/filter/IBaseFilterProvider.ts index d082bfe12..fc3301b11 100644 --- a/src/client/northstar/core/filter/IBaseFilterProvider.ts +++ b/src/client/northstar/core/filter/IBaseFilterProvider.ts @@ -1,4 +1,4 @@ -import { FilterModel } from '../filter/FilterModel' +import { FilterModel } from '../filter/FilterModel'; export interface IBaseFilterProvider { FilterModels: Array; diff --git a/src/client/northstar/core/filter/ValueComparision.ts b/src/client/northstar/core/filter/ValueComparision.ts index 1a3e461f5..80b1242a9 100644 --- a/src/client/northstar/core/filter/ValueComparision.ts +++ b/src/client/northstar/core/filter/ValueComparision.ts @@ -1,5 +1,5 @@ -import { Predicate } from '../../model/idea/idea' -import { Utils } from '../../utils/Utils' +import { Predicate } from '../../model/idea/idea'; +import { Utils } from '../../utils/Utils'; import { AttributeModel } from '../attribute/AttributeModel'; export class ValueComparison { @@ -15,15 +15,19 @@ export class ValueComparison { } public Equals(other: Object): boolean { - if (!Utils.EqualityHelper(this, other)) + if (!Utils.EqualityHelper(this, other)) { return false; - if (this.Predicate !== (other as ValueComparison).Predicate) + } + if (this.Predicate !== (other as ValueComparison).Predicate) { return false; + } let isComplex = (typeof this.Value === "object"); - if (!isComplex && this.Value !== (other as ValueComparison).Value) + if (!isComplex && this.Value !== (other as ValueComparison).Value) { return false; - if (isComplex && !this.Value.Equals((other as ValueComparison).Value)) + } + if (isComplex && !this.Value.Equals((other as ValueComparison).Value)) { return false; + } return true; } diff --git a/src/client/northstar/dash-fields/HistogramField.ts b/src/client/northstar/dash-fields/HistogramField.ts index fa2a9c008..6abde4677 100644 --- a/src/client/northstar/dash-fields/HistogramField.ts +++ b/src/client/northstar/dash-fields/HistogramField.ts @@ -41,7 +41,7 @@ export class HistogramField extends BasicField { data: this.toString(), _id: this.Id - } + }; } @action diff --git a/src/client/northstar/dash-nodes/HistogramBinPrimitiveCollection.ts b/src/client/northstar/dash-nodes/HistogramBinPrimitiveCollection.ts index cdae90c8b..6291ec1fc 100644 --- a/src/client/northstar/dash-nodes/HistogramBinPrimitiveCollection.ts +++ b/src/client/northstar/dash-nodes/HistogramBinPrimitiveCollection.ts @@ -1,4 +1,4 @@ -import React = require("react") +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"; @@ -29,7 +29,7 @@ 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!; } + private get sizeConverter() { return this._histoBox.SizeConverter; } public BinPrimitives: Array = new Array(); public HitGeom: PIXIRectangle = PIXIRectangle.EMPTY; @@ -99,13 +99,14 @@ export class HistogramBinPrimitiveCollection { private createHeatmapBinPrimitives(bin: Bin, brush: Brush, brushFactorSum: number): number { let unNormalizedValue = this.getBinValue(2, bin, brush.brushIndex!); - if (unNormalizedValue === undefined) + 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)) + 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); @@ -145,8 +146,9 @@ export class HistogramBinPrimitiveCollection { 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) + 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; } diff --git a/src/client/northstar/dash-nodes/HistogramBox.tsx b/src/client/northstar/dash-nodes/HistogramBox.tsx index ec9413649..7df59ef07 100644 --- a/src/client/northstar/dash-nodes/HistogramBox.tsx +++ b/src/client/northstar/dash-nodes/HistogramBox.tsx @@ -1,4 +1,4 @@ -import React = require("react") +import React = require("react"); import { action, computed, observable, reaction, runInAction, trace } from "mobx"; import { observer } from "mobx-react"; import Measure from "react-measure"; @@ -25,7 +25,7 @@ import { StyleConstants } from "../utils/StyleContants"; @observer export class HistogramBox extends React.Component { - public static LayoutString(fieldStr: string = "DataKey") { return FieldView.LayoutString(HistogramBox, fieldStr) } + public static LayoutString(fieldStr: string = "DataKey") { return FieldView.LayoutString(HistogramBox, fieldStr); } private _dropXRef = React.createRef(); private _dropYRef = React.createRef(); private _dropXDisposer?: DragManager.DragDropDisposer; @@ -92,15 +92,15 @@ export class HistogramBox extends React.Component { } 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.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))); + 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 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]); @@ -109,10 +109,12 @@ export class HistogramBox extends React.Component { } componentWillUnmount() { - if (this._dropXDisposer) + if (this._dropXDisposer) { this._dropXDisposer(); - if (this._dropYDisposer) + } + if (this._dropYDisposer) { this._dropYDisposer(); + } } activateHistogramOperation(catalog?: Catalog) { @@ -128,7 +130,7 @@ export class HistogramBox extends React.Component { 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[]); - return { l: brush, b: brushed[0].Id === proto.Id ? brushed[1] : brushed[0] } + return { l: brush, b: brushed[0].Id === proto.Id ? brushed[1] : brushed[0] }; })); }, { fireImmediately: true }); reaction(() => this.createOperationParamsCache, () => this.HistoOp.Update(), { fireImmediately: true }); @@ -146,7 +148,7 @@ export class HistogramBox extends React.Component { let roff = this.SizeConverter.RightOffset; let boff = this.SizeConverter.BottomOffset; return ( - runInAction(() => { this.PanelWidth = r.entry.width; this.PanelHeight = r.entry.height })}> + runInAction(() => { this.PanelWidth = r.entry.width; this.PanelHeight = r.entry.height; })}> {({ measureRef }) =>
@@ -168,7 +170,7 @@ export class HistogramBox extends React.Component {
} - ) + ); } } diff --git a/src/client/northstar/dash-nodes/HistogramBoxPrimitives.tsx b/src/client/northstar/dash-nodes/HistogramBoxPrimitives.tsx index a78703247..4c5bdb14b 100644 --- a/src/client/northstar/dash-nodes/HistogramBoxPrimitives.tsx +++ b/src/client/northstar/dash-nodes/HistogramBoxPrimitives.tsx @@ -1,4 +1,4 @@ -import React = require("react") +import React = require("react"); import { computed, observable, reaction, runInAction, trace, action } from "mobx"; import { observer } from "mobx-react"; import { Utils as DashUtils } from '../../../Utils'; @@ -28,17 +28,18 @@ export class HistogramBoxPrimitives extends React.Component this.drawRect(bp.Rect, bp.BarAxis, undefined, "border")); } @computed get barPrimitives() { let histoResult = this.props.HistoBox.HistogramResult; - if (!histoResult || !histoResult.bins || !this.props.HistoBox.VisualBinRanges.length) + if (!histoResult || !histoResult.bins || !this.props.HistoBox.VisualBinRanges.length) { return (null); + } let allBrushIndex = ModelHelpers.AllBrushIndex(histoResult); return Object.keys(histoResult.bins).reduce((prims: JSX.Element[], key: string) => { - let drawPrims = new HistogramBinPrimitiveCollection(histoResult!.bins![key], this.props.HistoBox); + 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)); + 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[]) + }, [] as JSX.Element[]); } componentDidMount() { @@ -47,8 +48,9 @@ export class HistogramBoxPrimitives extends React.Component bp.BrushIndex === allBrushIndex); - if (!rawAllBrushPrim) - return () => { } + if (!rawAllBrushPrim) { + return () => { }; + } let allBrushPrim = rawAllBrushPrim; return () => runInAction(() => { if (ArrayUtil.Contains(this.histoOp.FilterModels, filterModel)) { @@ -59,23 +61,25 @@ export class HistogramBoxPrimitives extends React.Component {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) + 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[])} - + ; } drawLine(xFrom: number, yFrom: number, width: number, height: number) { @@ -89,9 +93,9 @@ export class HistogramBoxPrimitives extends React.Component + let trans1Xpercent = `${xFrom / this.renderDimension * 100}%`; + let trans1Ypercent = `${yFrom / this.renderDimension * 100}%`; + return ; } drawRect(r: PIXIRectangle, barAxis: number, color: number | undefined, classExt: string, tapHandler: () => void = () => { }) { if (r.height < 0) { @@ -102,11 +106,11 @@ export class HistogramBoxPrimitives extends React.Component { if (e.button === 0) tapHandler() }} + return ( { if (e.button === 0) tapHandler(); }} x={transXpercent} width={`${widthXpercent}`} y={transYpercent} height={`${heightYpercent}`} fill={color ? `${LABColor.RGBtoHexString(color)}` : "transparent"} />); } render() { @@ -118,6 +122,6 @@ export class HistogramBoxPrimitives extends React.Component -
+
; } } \ 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 dd62e9146..5785fe838 100644 --- a/src/client/northstar/dash-nodes/HistogramLabelPrimitives.tsx +++ b/src/client/northstar/dash-nodes/HistogramLabelPrimitives.tsx @@ -1,4 +1,4 @@ -import React = require("react") +import React = require("react"); import { action, computed, reaction } from "mobx"; import { observer } from "mobx-react"; import { Utils as DashUtils } from '../../../Utils'; @@ -13,7 +13,7 @@ import { HistogramPrimitivesProps } from "./HistogramBoxPrimitives"; 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 }); + (fields) => HistogramLabelPrimitives.computeLabelAngle(fields[0], fields[1], this.props.HistoBox), { fireImmediately: true }); } @action @@ -32,8 +32,9 @@ export class HistogramLabelPrimitives extends React.ComponentFontStyles.AxisLabel.fontSize + 5))); sc.MaxLabelSizes[axis].coords[axis] + 5); @@ -52,8 +53,8 @@ export class HistogramLabelPrimitives extends React.Component @@ -61,7 +62,7 @@ export class HistogramLabelPrimitives extends React.Component
- ) + ); } return prims; }, [] as JSX.Element[]); @@ -73,7 +74,7 @@ export class HistogramLabelPrimitives extends React.Component {xaxislines} {yaxislines} -
+
; } } \ No newline at end of file diff --git a/src/client/northstar/manager/Gateway.ts b/src/client/northstar/manager/Gateway.ts index ba6fe2ad5..1c8d3fd73 100644 --- a/src/client/northstar/manager/Gateway.ts +++ b/src/client/northstar/manager/Gateway.ts @@ -1,4 +1,4 @@ -import { Catalog, OperationReference, Result, CompileResults } from "../model/idea/idea" +import { Catalog, OperationReference, Result, CompileResults } from "../model/idea/idea"; import { computed, observable, action } from "mobx"; export class Gateway { diff --git a/src/client/northstar/model/ModelExtensions.ts b/src/client/northstar/model/ModelExtensions.ts index e4bf77ed8..29f80d2d1 100644 --- a/src/client/northstar/model/ModelExtensions.ts +++ b/src/client/northstar/model/ModelExtensions.ts @@ -1,7 +1,7 @@ -import { AttributeParameters, Brush, MarginAggregateParameters, SingleDimensionAggregateParameters, Solution } from '../model/idea/idea' -import { Utils } from '../utils/Utils' +import { AttributeParameters, Brush, MarginAggregateParameters, SingleDimensionAggregateParameters, Solution } from '../model/idea/idea'; +import { Utils } from '../utils/Utils'; -import { FilterModel } from '../core/filter/FilterModel' +import { FilterModel } from '../core/filter/FilterModel'; (SingleDimensionAggregateParameters as any).prototype.Equals = function (other: Object) { if (!Utils.EqualityHelper(this, other)) return false; @@ -9,13 +9,13 @@ import { FilterModel } from '../core/filter/FilterModel' (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 (this).constructor.name === (other).constructor.name && + return (this).constructor.name === (other).constructor.name && this.rawName === other.rawName; - } + }; } { @@ -23,7 +23,7 @@ import { FilterModel } from '../core/filter/FilterModel' if (!Utils.EqualityHelper(this, other)) return false; if ((this as Solution).solutionId !== (other as Solution).solutionId) return false; return true; - } + }; } { @@ -35,7 +35,7 @@ import { FilterModel } from '../core/filter/FilterModel' if ((this as MarginAggregateParameters).aggregateFunction !== (other as MarginAggregateParameters).aggregateFunction) return false; return true; - } + }; } { @@ -44,5 +44,5 @@ import { FilterModel } from '../core/filter/FilterModel' 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 index 1a58e6180..ac807b41f 100644 --- a/src/client/northstar/model/ModelHelpers.ts +++ b/src/client/northstar/model/ModelHelpers.ts @@ -64,7 +64,7 @@ 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 = distinctAttributeParameters; @@ -106,7 +106,7 @@ export class ModelHelpers { { rawName: am.CodeName, visualizationHints: am.VisualizationHints, - id: (am as BackendAttributeModel).Id + id: (am).Id }); } else if (am instanceof CodeAttributeModel) { @@ -114,11 +114,11 @@ export class ModelHelpers { { rawName: am.CodeName, visualizationHints: am.VisualizationHints, - code: (am as CodeAttributeModel).Code + code: (am).Code }); } else { - throw new Exception() + throw new Exception(); } } diff --git a/src/client/northstar/model/binRanges/AlphabeticVisualBinRange.ts b/src/client/northstar/model/binRanges/AlphabeticVisualBinRange.ts index 995bf4e0b..120b034f2 100644 --- a/src/client/northstar/model/binRanges/AlphabeticVisualBinRange.ts +++ b/src/client/northstar/model/binRanges/AlphabeticVisualBinRange.ts @@ -1,5 +1,5 @@ -import { AlphabeticBinRange, BinLabel } from '../../model/idea/idea' -import { VisualBinRange } from './VisualBinRange' +import { AlphabeticBinRange, BinLabel } from '../../model/idea/idea'; +import { VisualBinRange } from './VisualBinRange'; export class AlphabeticVisualBinRange extends VisualBinRange { public DataBinRange: AlphabeticBinRange; diff --git a/src/client/northstar/model/binRanges/DateTimeVisualBinRange.ts b/src/client/northstar/model/binRanges/DateTimeVisualBinRange.ts index f5872aa4c..776e643cd 100644 --- a/src/client/northstar/model/binRanges/DateTimeVisualBinRange.ts +++ b/src/client/northstar/model/binRanges/DateTimeVisualBinRange.ts @@ -1,5 +1,5 @@ -import { DateTimeBinRange, DateTimeStep, DateTimeStepGranularity } from '../idea/idea' -import { VisualBinRange } from './VisualBinRange' +import { DateTimeBinRange, DateTimeStep, DateTimeStepGranularity } from '../idea/idea'; +import { VisualBinRange } from './VisualBinRange'; export class DateTimeVisualBinRange extends VisualBinRange { public DataBinRange: DateTimeBinRange; diff --git a/src/client/northstar/model/binRanges/NominalVisualBinRange.ts b/src/client/northstar/model/binRanges/NominalVisualBinRange.ts index 407ff3ea6..42509d797 100644 --- a/src/client/northstar/model/binRanges/NominalVisualBinRange.ts +++ b/src/client/northstar/model/binRanges/NominalVisualBinRange.ts @@ -1,5 +1,5 @@ -import { NominalBinRange, BinLabel } from '../../model/idea/idea' -import { VisualBinRange } from './VisualBinRange' +import { NominalBinRange, BinLabel } from '../../model/idea/idea'; +import { VisualBinRange } from './VisualBinRange'; export class NominalVisualBinRange extends VisualBinRange { public DataBinRange: NominalBinRange; diff --git a/src/client/northstar/model/binRanges/QuantitativeVisualBinRange.ts b/src/client/northstar/model/binRanges/QuantitativeVisualBinRange.ts index 80886416b..c579c8e5f 100644 --- a/src/client/northstar/model/binRanges/QuantitativeVisualBinRange.ts +++ b/src/client/northstar/model/binRanges/QuantitativeVisualBinRange.ts @@ -1,4 +1,4 @@ -import { QuantitativeBinRange } from '../idea/idea' +import { QuantitativeBinRange } from '../idea/idea'; import { VisualBinRange } from './VisualBinRange'; import { format } from "d3-format"; diff --git a/src/client/northstar/model/binRanges/VisualBinRange.ts b/src/client/northstar/model/binRanges/VisualBinRange.ts index a0766e494..449a22e91 100644 --- a/src/client/northstar/model/binRanges/VisualBinRange.ts +++ b/src/client/northstar/model/binRanges/VisualBinRange.ts @@ -1,4 +1,4 @@ -import { BinLabel } from '../../model/idea/idea' +import { BinLabel } from '../../model/idea/idea'; export abstract class VisualBinRange { diff --git a/src/client/northstar/model/binRanges/VisualBinRangeHelper.ts b/src/client/northstar/model/binRanges/VisualBinRangeHelper.ts index 63ee61909..9671e55f8 100644 --- a/src/client/northstar/model/binRanges/VisualBinRangeHelper.ts +++ b/src/client/northstar/model/binRanges/VisualBinRangeHelper.ts @@ -16,18 +16,18 @@ export class VisualBinRangeHelper { public static GetNonAggregateVisualBinRange(dataBinRange: BinRange): VisualBinRange { if (dataBinRange instanceof NominalBinRange) { - return new NominalVisualBinRange(dataBinRange as NominalBinRange); + return new NominalVisualBinRange(dataBinRange); } else if (dataBinRange instanceof QuantitativeBinRange) { - return new QuantitativeVisualBinRange(dataBinRange as QuantitativeBinRange); + return new QuantitativeVisualBinRange(dataBinRange); } else if (dataBinRange instanceof AlphabeticBinRange) { - return new AlphabeticVisualBinRange(dataBinRange as AlphabeticBinRange); + return new AlphabeticVisualBinRange(dataBinRange); } else if (dataBinRange instanceof DateTimeBinRange) { - return new DateTimeVisualBinRange(dataBinRange as DateTimeBinRange); + return new DateTimeVisualBinRange(dataBinRange); } - throw new Exception() + throw new Exception(); } public static GetVisualBinRange(distinctAttributeParameters: AttributeParameters | undefined, dataBinRange: BinRange, histoResult: HistogramResult, attr: AttributeTransformationModel, chartType: ChartType): VisualBinRange { @@ -51,13 +51,13 @@ export class VisualBinRangeHelper { } } } - }; + } 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!), + Math.max(0, (visualBinRange).DataBinRange.maxValue!), SETTINGS_X_BINS, false); } else if (chartType === ChartType.SinglePoint) { diff --git a/src/client/northstar/operations/BaseOperation.ts b/src/client/northstar/operations/BaseOperation.ts index a14337763..c6d5f0a15 100644 --- a/src/client/northstar/operations/BaseOperation.ts +++ b/src/client/northstar/operations/BaseOperation.ts @@ -1,4 +1,4 @@ -import { FilterModel } from '../core/filter/FilterModel' +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'; @@ -62,8 +62,9 @@ export abstract class BaseOperation { } let operationParameters = this.CreateOperationParameters(); - if (this.Result) - this.Result.progress = 0; // bcz: used to set Result to undefined, but that causes the display to blink + 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; @@ -97,7 +98,7 @@ export abstract class BaseOperation { pollPromise.Start(async () => { let result = await Gateway.Instance.GetResult(resultParameters.toJSON()); if (result instanceof ErrorResult) { - throw new Error((result as ErrorResult).message); + throw new Error((result).message); } if (this.RequestSalt === pollPromise.RequestSalt) { if (result && (!this.Result || this.Result.progress !== result.progress)) { diff --git a/src/client/northstar/operations/HistogramOperation.ts b/src/client/northstar/operations/HistogramOperation.ts index a3ddc1c98..760106023 100644 --- a/src/client/northstar/operations/HistogramOperation.ts +++ b/src/client/northstar/operations/HistogramOperation.ts @@ -62,7 +62,7 @@ export class HistogramOperation extends BaseOperation implements IBaseFilterCons @computed public get FilterString(): string { let filterModels: FilterModel[] = []; - return FilterModel.GetFilterModelsRecursive(this, new Set(), filterModels, true) + return FilterModel.GetFilterModelsRecursive(this, new Set(), filterModels, true); } @computed diff --git a/src/client/northstar/utils/ArrayUtil.ts b/src/client/northstar/utils/ArrayUtil.ts index a52ca6d96..12b8d8e77 100644 --- a/src/client/northstar/utils/ArrayUtil.ts +++ b/src/client/northstar/utils/ArrayUtil.ts @@ -50,7 +50,7 @@ export class ArrayUtil { if (filtered.length > 0) { return filtered[0]; } - throw new Exception() + throw new Exception(); } public static FirstOrDefault(arr: T[], predicate: (x: any) => boolean): T | undefined { diff --git a/src/client/northstar/utils/Extensions.ts b/src/client/northstar/utils/Extensions.ts index 7c2b7fc9d..df14d4da0 100644 --- a/src/client/northstar/utils/Extensions.ts +++ b/src/client/northstar/utils/Extensions.ts @@ -6,7 +6,7 @@ interface String { String.prototype.ReplaceAll = function (toReplace: string, replacement: string): string { var target = this; return target.split(toReplace).join(replacement); -} +}; String.prototype.Truncate = function (length: number, replacement: string): String { var target = this; @@ -14,7 +14,7 @@ String.prototype.Truncate = function (length: number, replacement: string): Stri target = target.slice(0, Math.max(0, length - replacement.length)) + replacement; } return target; -} +}; interface Math { log10(val: number): number; @@ -22,7 +22,7 @@ interface Math { Math.log10 = function (val: number): number { return Math.log(val) / Math.LN10; -} +}; declare interface ObjectConstructor { assign(...objects: Object[]): Object; diff --git a/src/client/northstar/utils/GeometryUtil.ts b/src/client/northstar/utils/GeometryUtil.ts index 6d8acea20..d5220c479 100644 --- a/src/client/northstar/utils/GeometryUtil.ts +++ b/src/client/northstar/utils/GeometryUtil.ts @@ -8,15 +8,19 @@ export class GeometryUtil { let minY: number = Number.MAX_VALUE; let maxX: number = Number.MIN_VALUE; let maxY: number = Number.MIN_VALUE; - for (var i = 0; i < points.length; i++) { - if (points[i].x < minX) - minX = points[i].x; - if (points[i].y < minY) - minY = points[i].y; - if (points[i].x > maxX) - maxX = points[i].x; - if (points[i].y > maxY) - maxY = points[i].y; + for (const point of points) { + if (point.x < minX) { + minX = point.x; + } + if (point.y < minY) { + minY = point.y; + } + if (point.x > maxX) { + maxX = point.x; + } + if (point.y > maxY) { + maxY = point.y; + } } return new PIXIRectangle(minX * scale - padding, minY * scale - padding, (maxX - minX) * scale + padding * 2, (maxY - minY) * scale + padding * 2); } @@ -35,7 +39,7 @@ export class GeometryUtil { nx = (cos * (x - cx)) + (sin * (y - cy)) + cx, ny = (cos * (y - cy)) - (sin * (x - cx)) + cy; return new PIXIPoint(nx, ny); - } + }; return points.map(p => rotate(center.x, center.y, p.x, p.y, angle)); } @@ -54,9 +58,9 @@ export class GeometryUtil { return []; } - for (let v = 0; v < points.length; v++) { - x = points[v].x; - y = points[v].y; + for (const point of points) { + x = point.x; + y = point.y; sum_x += x; sum_y += y; sum_xx += x * x; @@ -68,8 +72,8 @@ export class GeometryUtil { let b = (sum_y / count) - (m * sum_x) / count; let result: PIXIPoint[] = new Array(); - for (let v = 0; v < points.length; v++) { - x = points[v].x; + for (const point of points) { + x = point.x; y = x * m + b; result.push(new PIXIPoint(x, y)); } diff --git a/src/client/northstar/utils/MathUtil.ts b/src/client/northstar/utils/MathUtil.ts index 7aa255096..4b44f40c3 100644 --- a/src/client/northstar/utils/MathUtil.ts +++ b/src/client/northstar/utils/MathUtil.ts @@ -16,11 +16,11 @@ export class PIXIRectangle { public x: number; public y: number; public width: number; - public height: number - public get left() { return this.x } + public height: number; + public get left() { return this.x; } public get right() { return this.x + this.width; } - public get top() { return this.y } - public get bottom() { return this.top + this.height } + 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; @@ -127,14 +127,18 @@ export class MathUtil { } public static PointInPIXIRectangle(p: PIXIPoint, rect: PIXIRectangle): boolean { - if (p.x < rect.left - this.EPSILON) + if (p.x < rect.left - this.EPSILON) { return false; - if (p.x > rect.right + this.EPSILON) + } + if (p.x > rect.right + this.EPSILON) { return false; - if (p.y < rect.top - this.EPSILON) + } + if (p.y < rect.top - this.EPSILON) { return false; - if (p.y > rect.bottom + this.EPSILON) + } + if (p.y > rect.bottom + this.EPSILON) { return false; + } return true; } @@ -145,23 +149,27 @@ export class MathUtil { var r3 = new PIXIPoint(rect.right, rect.bottom); var r4 = new PIXIPoint(rect.left, rect.bottom); var ret = new Array(); - var dist = this.Dist(lineFrom, lineTo) + var dist = this.Dist(lineFrom, lineTo); var inter = this.LineSegmentIntersection(lineFrom, lineTo, r1, r2); if (inter && this.PointInPIXIRectangle(inter, rect) && - this.Dist(inter, lineFrom) < dist && this.Dist(inter, lineTo) < dist) + this.Dist(inter, lineFrom) < dist && this.Dist(inter, lineTo) < dist) { ret.push(inter); + } inter = this.LineSegmentIntersection(lineFrom, lineTo, r2, r3); if (inter && this.PointInPIXIRectangle(inter, rect) && - this.Dist(inter, lineFrom) < dist && this.Dist(inter, lineTo) < dist) + this.Dist(inter, lineFrom) < dist && this.Dist(inter, lineTo) < dist) { ret.push(inter); + } inter = this.LineSegmentIntersection(lineFrom, lineTo, r3, r4); if (inter && this.PointInPIXIRectangle(inter, rect) && - this.Dist(inter, lineFrom) < dist && this.Dist(inter, lineTo) < dist) + this.Dist(inter, lineFrom) < dist && this.Dist(inter, lineTo) < dist) { ret.push(inter); + } inter = this.LineSegmentIntersection(lineFrom, lineTo, r4, r1); if (inter && this.PointInPIXIRectangle(inter, rect) && - this.Dist(inter, lineFrom) < dist && this.Dist(inter, lineTo) < dist) + this.Dist(inter, lineFrom) < dist && this.Dist(inter, lineTo) < dist) { ret.push(inter); + } return ret; } @@ -178,7 +186,7 @@ export class MathUtil { } public static Dot(p1: PIXIPoint, p2: PIXIPoint): number { - return p1.x * p2.x + p1.y * p2.y + return p1.x * p2.x + p1.y * p2.y; } public static Normalize(p1: PIXIPoint) { @@ -193,7 +201,7 @@ export class MathUtil { public static DistSquared(p1: PIXIPoint, p2: PIXIPoint): number { const a = p1.x - p2.x; const b = p1.y - p2.y; - return (a * a + b * b) + return (a * a + b * b); } public static RectIntersectsRect(r1: PIXIRectangle, r2: PIXIRectangle): boolean { diff --git a/src/client/northstar/utils/SizeConverter.ts b/src/client/northstar/utils/SizeConverter.ts index b5c4a16ab..a52890ed9 100644 --- a/src/client/northstar/utils/SizeConverter.ts +++ b/src/client/northstar/utils/SizeConverter.ts @@ -32,8 +32,8 @@ export class SizeConverter { this.Initialized++; 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 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: 75 }; // RenderUtils.MeasureText(FontStyles.Default.fontFamily.toString(), 12, // FontStyles.AxisLabel.fontSize as number, //xLabelStrings[0]!.slice(0, 20)) // StyleConstants.MAX_CHAR_FOR_HISTOGRAM_LABELS)); @@ -62,19 +62,20 @@ export class SizeConverter { public DataToScreenPointRange(axis: number, bin: Bin, aggregateKey: AggregateKey) { var value = ModelHelpers.GetAggregateResult(bin, aggregateKey) as DoubleValueAggregateResult; - if (value && value.hasResult) + if (value && value.hasResult) { return [this.DataToScreenCoord(value.result!, axis) - 5, this.DataToScreenCoord(value.result!, axis) + 5]; + } return [undefined, undefined]; } 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))] + 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))] + return [this.DataToScreenY(value), this.DataToScreenY(visualBinRanges[index].AddStep(value))]; } public DataToScreenX(x: number): number { @@ -85,8 +86,9 @@ export class SizeConverter { return flip ? (this.RenderDimension) - retY : retY; } public DataToScreenCoord(v: number, axis: number) { - if (axis === 0) + if (axis === 0) { return this.DataToScreenX(v); + } return this.DataToScreenY(v); } public DataToScreenRange(minVal: number, maxVal: number, axis: number) { @@ -94,6 +96,6 @@ export class SizeConverter { 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 } + return { xFrom, yFrom, xTo, yTo }; } } \ No newline at end of file diff --git a/src/client/northstar/utils/StyleContants.ts b/src/client/northstar/utils/StyleContants.ts index ac8617e3b..e9b6e0297 100644 --- a/src/client/northstar/utils/StyleContants.ts +++ b/src/client/northstar/utils/StyleContants.ts @@ -11,7 +11,7 @@ export class StyleConstants { 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 BRUSH_PALETTE: number[] = [0x42b43c, 0xfa217f, 0x6a9c75, 0xfb5de7, 0x25b8ea, 0x9b5bc4, 0xda9f63, 0xe23209, 0xfb899b, 0x94a6fd]; static GAP: number = 3; static BACKGROUND_COLOR: number = 0xF3F3F3; diff --git a/src/client/northstar/utils/Utils.ts b/src/client/northstar/utils/Utils.ts index c96b4cbd9..d071dec62 100644 --- a/src/client/northstar/utils/Utils.ts +++ b/src/client/northstar/utils/Utils.ts @@ -1,7 +1,7 @@ -import { IBaseBrushable } from '../core/brusher/IBaseBrushable' -import { IBaseFilterConsumer } from '../core/filter/IBaseFilterConsumer' -import { IBaseFilterProvider } from '../core/filter/IBaseFilterProvider' -import { AggregateFunction } from '../model/idea/idea' +import { IBaseBrushable } from '../core/brusher/IBaseBrushable'; +import { IBaseFilterConsumer } from '../core/filter/IBaseFilterConsumer'; +import { IBaseFilterProvider } from '../core/filter/IBaseFilterProvider'; +import { AggregateFunction } from '../model/idea/idea'; export class Utils { diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index fb489edb6..f38b8ca75 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -1,7 +1,7 @@ -import React = require('react') +import React = require('react'); import { observer } from 'mobx-react'; import { observable, action, computed } from 'mobx'; -import { Document } from "../../fields/Document" +import { Document } from "../../fields/Document"; import { DocumentView } from '../views/nodes/DocumentView'; import { KeyStore } from '../../fields/KeyStore'; import { FieldWaiting } from '../../fields/Field'; @@ -50,7 +50,7 @@ export class DocumentManager { if (docSrc && docSrc !== FieldWaiting && Object.is(docSrc, toFind)) { toReturn = view; } - }) + }); return (toReturn); } @@ -71,7 +71,7 @@ export class DocumentManager { toReturn.push(view); } } - }) + }); return (toReturn); } @@ -86,8 +86,8 @@ export class DocumentManager { let linkToDoc = link.GetT(KeyStore.LinkedToDocs, Document); if (linkToDoc && linkToDoc !== FieldWaiting) { DocumentManager.Instance.getDocumentViews(linkToDoc).map(docView1 => { - pairs.push({ a: dv, b: docView1, l: link }) - }) + pairs.push({ a: dv, b: docView1, l: link }); + }); } } return pairs; diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index f95b2c29d..4849ae9f7 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -103,7 +103,7 @@ export namespace DragManager { element.addEventListener("dashOnDrop", handler); return () => { element.removeEventListener("dashOnDrop", handler); - delete element.dataset.canDrop + delete element.dataset.canDrop; }; } @@ -216,8 +216,9 @@ export namespace DragManager { const moveHandler = (e: PointerEvent) => { e.stopPropagation(); e.preventDefault(); - if (dragData instanceof DocumentDragData) + if (dragData instanceof DocumentDragData) { dragData.aliasOnDrop = e.ctrlKey || e.altKey; + } if (e.shiftKey) { abortDrag(); CollectionDockingView.Instance.StartOtherDrag(docs, { diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index 2a3c1da6e..92944bec0 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -1,13 +1,13 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { Schema, NodeSpec, MarkSpec, DOMOutputSpecArray, NodeType } from "prosemirror-model" -import { joinUp, lift, setBlockType, toggleMark, wrapIn } from 'prosemirror-commands' -import { redo, undo } from 'prosemirror-history' -import { orderedList, bulletList, listItem, } from 'prosemirror-schema-list' +import { Schema, NodeSpec, MarkSpec, DOMOutputSpecArray, NodeType } from "prosemirror-model"; +import { joinUp, lift, setBlockType, toggleMark, wrapIn } from 'prosemirror-commands'; +import { redo, undo } from 'prosemirror-history'; +import { orderedList, bulletList, listItem, } from 'prosemirror-schema-list'; import { EditorState, Transaction, NodeSelection, } from "prosemirror-state"; import { EditorView, } from "prosemirror-view"; const pDOM: DOMOutputSpecArray = ["p", 0], blockquoteDOM: DOMOutputSpecArray = ["blockquote", 0], hrDOM: DOMOutputSpecArray = ["hr"], - preDOM: DOMOutputSpecArray = ["pre", ["code", 0]], brDOM: DOMOutputSpecArray = ["br"], ulDOM: DOMOutputSpecArray = ["ul", 0] + preDOM: DOMOutputSpecArray = ["pre", ["code", 0]], brDOM: DOMOutputSpecArray = ["br"], ulDOM: DOMOutputSpecArray = ["ul", 0]; // :: Object @@ -24,7 +24,7 @@ export const nodes: { [index: string]: NodeSpec } = { content: "inline*", group: "block", parseDOM: [{ tag: "p" }], - toDOM() { return pDOM } + toDOM() { return pDOM; } }, // :: NodeSpec A blockquote (`
`) wrapping one or more blocks. @@ -33,14 +33,14 @@ export const nodes: { [index: string]: NodeSpec } = { group: "block", defining: true, parseDOM: [{ tag: "blockquote" }], - toDOM() { return blockquoteDOM } + toDOM() { return blockquoteDOM; } }, // :: NodeSpec A horizontal rule (`
`). horizontal_rule: { group: "block", parseDOM: [{ tag: "hr" }], - toDOM() { return hrDOM } + toDOM() { return hrDOM; } }, // :: NodeSpec A heading textblock, with a `level` attribute that @@ -57,7 +57,7 @@ export const nodes: { [index: string]: NodeSpec } = { { tag: "h4", attrs: { level: 4 } }, { tag: "h5", attrs: { level: 5 } }, { tag: "h6", attrs: { level: 6 } }], - toDOM(node: any) { return ["h" + node.attrs.level, 0] } + toDOM(node: any) { return ["h" + node.attrs.level, 0]; } }, // :: NodeSpec A code listing. Disallows marks or non-text inline @@ -70,7 +70,7 @@ export const nodes: { [index: string]: NodeSpec } = { code: true, defining: true, parseDOM: [{ tag: "pre", preserveWhitespace: "full" }], - toDOM() { return preDOM } + toDOM() { return preDOM; } }, // :: NodeSpec The text node. @@ -96,10 +96,10 @@ export const nodes: { [index: string]: NodeSpec } = { src: dom.getAttribute("src"), title: dom.getAttribute("title"), alt: dom.getAttribute("alt") - } + }; } }], - toDOM(node: any) { return ["img", node.attrs] } + toDOM(node: any) { return ["img", node.attrs]; } }, // :: NodeSpec A hard line break, represented in the DOM as `
`. @@ -108,7 +108,7 @@ export const nodes: { [index: string]: NodeSpec } = { group: "inline", selectable: false, parseDOM: [{ tag: "br" }], - toDOM() { return brDOM } + toDOM() { return brDOM; } }, ordered_list: { @@ -136,7 +136,7 @@ export const nodes: { [index: string]: NodeSpec } = { ...listItem, content: 'paragraph block*' } -} +}; const emDOM: DOMOutputSpecArray = ["em", 0]; const strongDOM: DOMOutputSpecArray = ["strong", 0]; @@ -156,17 +156,17 @@ export const marks: { [index: string]: MarkSpec } = { inclusive: false, parseDOM: [{ tag: "a[href]", getAttrs(dom: any) { - return { href: dom.getAttribute("href"), title: dom.getAttribute("title") } + return { href: dom.getAttribute("href"), title: dom.getAttribute("title") }; } }], - toDOM(node: any) { return ["a", node.attrs, 0] } + toDOM(node: any) { return ["a", node.attrs, 0]; } }, // :: MarkSpec An emphasis mark. Rendered as an `` element. // Has parse rules that also match `` and `font-style: italic`. em: { parseDOM: [{ tag: "i" }, { tag: "em" }, { style: "font-style=italic" }], - toDOM() { return emDOM } + toDOM() { return emDOM; } }, // :: MarkSpec A strong mark. Rendered as ``, parse rules @@ -175,7 +175,7 @@ export const marks: { [index: string]: MarkSpec } = { parseDOM: [{ tag: "strong" }, { tag: "b" }, { style: "font-weight" }], - toDOM() { return strongDOM } + toDOM() { return strongDOM; } }, underline: { @@ -221,9 +221,9 @@ export const marks: { [index: string]: MarkSpec } = { // :: MarkSpec Code font mark. Represented as a `` element. code: { parseDOM: [{ tag: "code" }], - toDOM() { return codeDOM } + toDOM() { return codeDOM; } } -} +}; // :: Schema // This schema rougly corresponds to the document schema used by @@ -233,4 +233,4 @@ export const marks: { [index: string]: MarkSpec } = { // // To reuse elements from this schema, extend or read from its // `spec.nodes` and `spec.marks` [properties](#model.Schema.spec). -export const schema = new Schema({ nodes, marks }) \ No newline at end of file +export const schema = new Schema({ nodes, marks }); \ No newline at end of file diff --git a/src/client/util/Scripting.ts b/src/client/util/Scripting.ts index bf9b8266f..468484928 100644 --- a/src/client/util/Scripting.ts +++ b/src/client/util/Scripting.ts @@ -14,7 +14,7 @@ import { ListField } from "../../fields/ListField"; // import * as typescriptes5 from '!!raw-loader!../../../node_modules/typescript/lib/lib.es5.d.ts' // @ts-ignore -import * as typescriptlib from '!!raw-loader!./type_decls.d' +import * as typescriptlib from '!!raw-loader!./type_decls.d'; import { Documents } from "../documents/Documents"; import { Key } from "../../fields/Key"; @@ -50,7 +50,7 @@ function Run(script: string | undefined, customParams: string[], diagnostics: an let fieldTypes = [Document, NumberField, TextField, ImageField, RichTextField, ListField, Key]; let paramNames = ["KeyStore", "Documents", ...fieldTypes.map(fn => fn.name)]; - let params: any[] = [KeyStore, Documents, ...fieldTypes] + let params: any[] = [KeyStore, Documents, ...fieldTypes]; let compiledFunction = new Function(...paramNames, `return ${script}`); let run = (args: { [name: string]: any } = {}): ScriptResult => { let argsArray: any[] = []; @@ -67,7 +67,7 @@ function Run(script: string | undefined, customParams: string[], diagnostics: an } catch (error) { return { success: false, error }; } - } + }; return { compiled: true, run }; } @@ -90,14 +90,14 @@ class ScriptingCompilerHost { } // getDefaultLibFileName(options: ts.CompilerOptions): string { getDefaultLibFileName(options: any): string { - return 'node_modules/typescript/lib/lib.d.ts' // No idea what this means... + return 'node_modules/typescript/lib/lib.d.ts'; // No idea what this means... } writeFile(fileName: string, content: string) { const file = this.files.find(file => file.fileName === fileName); if (file) { file.content = content; } else { - this.files.push({ fileName, content }) + this.files.push({ fileName, content }); } } getCurrentDirectory(): string { diff --git a/src/client/util/ScrollBox.tsx b/src/client/util/ScrollBox.tsx index b6b088170..a209874a3 100644 --- a/src/client/util/ScrollBox.tsx +++ b/src/client/util/ScrollBox.tsx @@ -1,4 +1,4 @@ -import React = require("react") +import React = require("react"); export class ScrollBox extends React.Component { onWheel = (e: React.WheelEvent) => { @@ -16,6 +16,6 @@ export class ScrollBox extends React.Component { }} onWheel={this.onWheel}> {this.props.children}
- ) + ); } } \ No newline at end of file diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts index 1bb15c86a..5ddaafc72 100644 --- a/src/client/util/SelectionManager.ts +++ b/src/client/util/SelectionManager.ts @@ -23,7 +23,7 @@ export namespace SelectionManager { @action DeselectAll(): void { - manager.SelectedDocuments.map(dv => dv.props.onActiveChanged(false)) + manager.SelectedDocuments.map(dv => dv.props.onActiveChanged(false)); manager.SelectedDocuments = []; } } @@ -46,7 +46,7 @@ export namespace SelectionManager { } } - manager.DeselectAll() + manager.DeselectAll(); if (found) manager.SelectDoc(found, false); Main.Instance.SetTextDoc(undefined, undefined); } diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx index 913472aa0..bd5753093 100644 --- a/src/client/util/TooltipTextMenu.tsx +++ b/src/client/util/TooltipTextMenu.tsx @@ -5,12 +5,12 @@ import { keymap } from "prosemirror-keymap"; import { EditorState, Transaction, NodeSelection } from "prosemirror-state"; import { EditorView } from "prosemirror-view"; import { schema } from "./RichTextSchema"; -import { Schema, NodeType } from "prosemirror-model" -import React = require("react") +import { Schema, NodeType } from "prosemirror-model"; +import React = require("react"); import "./TooltipTextMenu.scss"; const { toggleMark, setBlockType, wrapIn } = require("prosemirror-commands"); -import { library } from '@fortawesome/fontawesome-svg-core' -import { wrapInList, bulletList } from 'prosemirror-schema-list' +import { library } from '@fortawesome/fontawesome-svg-core'; +import { wrapInList, bulletList } from 'prosemirror-schema-list'; import { faListUl } from '@fortawesome/free-solid-svg-icons'; @@ -39,7 +39,7 @@ export class TooltipTextMenu { { command: toggleMark(schema.marks.subscript), dom: this.icon("s", "subscript") }, //this doesn't work currently - look into notion of active block { command: wrapInList(schema.nodes.bullet_list), dom: this.icon(":", "bullets") }, - ] + ]; items.forEach(({ dom }) => this.tooltip.appendChild(dom)); //pointer down handler to activate button effects @@ -52,8 +52,8 @@ export class TooltipTextMenu { //uncomment this if we want the bullet button to disappear if current selection is bulleted // dom.style.display = active ? "" : "none" } - }) - }) + }); + }); this.update(view, undefined); } @@ -99,32 +99,32 @@ export class TooltipTextMenu { return { command: setBlockType(schema.nodes.heading, { level }), dom: this.icon("H" + level, "heading") - } + }; } //updates the tooltip menu when the selection changes update(view: EditorView, lastState: EditorState | undefined) { - let state = view.state + let state = view.state; // Don't do anything if the document/selection didn't change if (lastState && lastState.doc.eq(state.doc) && - lastState.selection.eq(state.selection)) return + lastState.selection.eq(state.selection)) return; // Hide the tooltip if the selection is empty if (state.selection.empty) { - this.tooltip.style.display = "none" - return + this.tooltip.style.display = "none"; + return; } // Otherwise, reposition it and update its content - this.tooltip.style.display = "" - let { from, to } = state.selection - let start = view.coordsAtPos(from), end = view.coordsAtPos(to) + this.tooltip.style.display = ""; + let { from, to } = state.selection; + let start = view.coordsAtPos(from), end = view.coordsAtPos(to); // The box in which the tooltip is positioned, to use as base - let box = this.tooltip.offsetParent!.getBoundingClientRect() + let box = this.tooltip.offsetParent!.getBoundingClientRect(); // Find a center-ish x position from the selection endpoints (when // crossing lines, end may be more to the left) - let left = Math.max((start.left + end.left) / 2, start.left + 3) - this.tooltip.style.left = (left - box.left) + "px" + let left = Math.max((start.left + end.left) / 2, start.left + 3); + this.tooltip.style.left = (left - box.left) + "px"; let width = Math.abs(start.left - end.left) / 2; let mid = Math.min(start.left, end.left) + width; @@ -133,5 +133,5 @@ export class TooltipTextMenu { this.tooltip.style.bottom = (box.bottom - start.top) + "px"; } - destroy() { this.tooltip.remove() } + destroy() { this.tooltip.remove(); } } \ No newline at end of file diff --git a/src/client/util/Transform.ts b/src/client/util/Transform.ts index ed4282874..e9170ec36 100644 --- a/src/client/util/Transform.ts +++ b/src/client/util/Transform.ts @@ -62,19 +62,19 @@ export class Transform { return this; } - translated = (x: number, y: number): Transform => this.copy().translate(x, y) + translated = (x: number, y: number): Transform => this.copy().translate(x, y); - preTranslated = (x: number, y: number): Transform => this.copy().preTranslate(x, y) + preTranslated = (x: number, y: number): Transform => this.copy().preTranslate(x, y); - scaled = (scale: number): Transform => this.copy().scale(scale) + scaled = (scale: number): Transform => this.copy().scale(scale); - scaledAbout = (scale: number, x: number, y: number): Transform => this.copy().scaleAbout(scale, x, y) + scaledAbout = (scale: number, x: number, y: number): Transform => this.copy().scaleAbout(scale, x, y); - preScaled = (scale: number): Transform => this.copy().preScale(scale) + preScaled = (scale: number): Transform => this.copy().preScale(scale); - transformed = (transform: Transform): Transform => this.copy().transform(transform) + transformed = (transform: Transform): Transform => this.copy().transform(transform); - preTransformed = (transform: Transform): Transform => this.copy().preTransform(transform) + preTransformed = (transform: Transform): Transform => this.copy().preTransform(transform); transformPoint = (x: number, y: number): [number, number] => { x *= this._scale; @@ -84,7 +84,7 @@ export class Transform { return [x, y]; } - transformDirection = (x: number, y: number): [number, number] => [x * this._scale, y * this._scale] + transformDirection = (x: number, y: number): [number, number] => [x * this._scale, y * this._scale]; transformBounds(x: number, y: number, width: number, height: number): { x: number, y: number, width: number, height: number } { [x, y] = this.transformPoint(x, y); @@ -92,8 +92,8 @@ export class Transform { return { x, y, width, height }; } - inverse = () => new Transform(-this._translateX / this._scale, -this._translateY / this._scale, 1 / this._scale) + inverse = () => new Transform(-this._translateX / this._scale, -this._translateY / this._scale, 1 / this._scale); - copy = () => new Transform(this._translateX, this._translateY, this._scale) + copy = () => new Transform(this._translateX, this._translateY, this._scale); } \ No newline at end of file diff --git a/src/client/util/TypedEvent.ts b/src/client/util/TypedEvent.ts index 1b251da25..532ba78eb 100644 --- a/src/client/util/TypedEvent.ts +++ b/src/client/util/TypedEvent.ts @@ -36,5 +36,5 @@ export class TypedEvent { this.listenersOncer = []; } - pipe = (te: TypedEvent): Disposable => this.on((e) => te.emit(e)) + pipe = (te: TypedEvent): Disposable => this.on((e) => te.emit(e)); } \ No newline at end of file diff --git a/src/client/util/UndoManager.ts b/src/client/util/UndoManager.ts index b4ea4acae..27aed4bac 100644 --- a/src/client/util/UndoManager.ts +++ b/src/client/util/UndoManager.ts @@ -1,5 +1,5 @@ import { observable, action } from "mobx"; -import 'source-map-support/register' +import 'source-map-support/register'; import { Without } from "../../Utils"; import { string } from "prop-types"; @@ -31,9 +31,9 @@ function propertyDecorator(target: any, key: string | symbol) { batch.end(); } } - }) + }); } - }) + }); } export function undoBatch(target: any, key: string | symbol, descriptor?: TypedPropertyDescriptor): any; @@ -43,11 +43,11 @@ export function undoBatch(target: any, key?: string | symbol, descriptor?: Typed return function () { let batch = UndoManager.StartBatch(""); try { - return target.apply(undefined, arguments) + return target.apply(undefined, arguments); } finally { batch.end(); } - } + }; } if (!descriptor) { propertyDecorator(target, key); @@ -58,11 +58,11 @@ export function undoBatch(target: any, key?: string | symbol, descriptor?: Typed descriptor.value = function (...args: any[]) { let batch = UndoManager.StartBatch(getBatchName(target, key)); try { - return oldFunction.apply(this, args) + return oldFunction.apply(this, args); } finally { batch.end(); } - } + }; return descriptor; } @@ -117,8 +117,8 @@ export namespace UndoManager { EndBatch(cancel); } - end = () => { this.dispose(false); } - cancel = () => { this.dispose(true); } + end = () => { this.dispose(false); }; + cancel = () => { this.dispose(true); }; } export function StartBatch(batchName: string): Batch { @@ -138,7 +138,7 @@ export namespace UndoManager { redoStack.length = 0; currentBatch = undefined; } - }) + }); export function RunInBatch(fn: () => void, batchName: string) { let batch = StartBatch(batchName); @@ -166,7 +166,7 @@ export namespace UndoManager { undoing = false; redoStack.push(commands); - }) + }); export const Redo = action(() => { if (redoStack.length === 0) { @@ -185,6 +185,6 @@ export namespace UndoManager { undoing = false; undoStack.push(commands); - }) + }); } \ No newline at end of file diff --git a/src/client/views/ContextMenu.tsx b/src/client/views/ContextMenu.tsx index cfa8ea7b7..615a928ad 100644 --- a/src/client/views/ContextMenu.tsx +++ b/src/client/views/ContextMenu.tsx @@ -2,11 +2,11 @@ import React = require("react"); import { ContextMenuItem, ContextMenuProps } from "./ContextMenuItem"; import { observable, action } from "mobx"; import { observer } from "mobx-react"; -import "./ContextMenu.scss" +import "./ContextMenu.scss"; @observer export class ContextMenu extends React.Component { - static Instance: ContextMenu + static Instance: ContextMenu; @observable private _items: Array = [{ description: "test", event: (e: React.MouseEvent) => e.preventDefault() }]; @observable private _pageX: number = 0; @@ -22,15 +22,15 @@ export class ContextMenu extends React.Component { constructor(props: Readonly<{}>) { super(props); - this.ref = React.createRef() + this.ref = React.createRef(); ContextMenu.Instance = this; } @action clearItems() { - this._items = [] - this._display = "none" + this._items = []; + this._display = "none"; } @action @@ -56,7 +56,7 @@ export class ContextMenu extends React.Component { this._searchString = ""; - this._display = "flex" + this._display = "flex"; } intersects = (x: number, y: number): boolean => { @@ -86,7 +86,7 @@ export class ContextMenu extends React.Component { {this._items.filter(prop => prop.description.toLowerCase().indexOf(this._searchString.toLowerCase()) !== -1). map(prop => )}
- ) + ); } @action diff --git a/src/client/views/ContextMenuItem.tsx b/src/client/views/ContextMenuItem.tsx index 4801c1555..70813f0dd 100644 --- a/src/client/views/ContextMenuItem.tsx +++ b/src/client/views/ContextMenuItem.tsx @@ -11,7 +11,7 @@ export interface SubmenuProps { } export interface ContextMenuItemProps { - type: ContextMenuProps | SubmenuProps + type: ContextMenuProps | SubmenuProps; } export class ContextMenuItem extends React.Component { @@ -20,6 +20,6 @@ export class ContextMenuItem extends React.Component {
{this.props.description}
- ) + ); } } \ No newline at end of file diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 285d145a2..b29fb6a2b 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -21,8 +21,8 @@ export const Flyout = higflyout.default; @observer export class DocumentDecorations extends React.Component<{}, { value: string }> { - static Instance: DocumentDecorations - private _resizer = "" + static Instance: DocumentDecorations; + private _resizer = ""; private _isPointerDown = false; private keyinput: React.RefObject; private _documents: DocumentView[] = SelectionManager.SelectedDocuments(); @@ -40,8 +40,8 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> constructor(props: Readonly<{}>) { - super(props) - DocumentDecorations.Instance = this + super(props); + DocumentDecorations.Instance = this; this.handleChange = this.handleChange.bind(this); this.keyinput = React.createRef(); } @@ -49,7 +49,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> @action handleChange = (event: any) => { this._title = event.target.value; - }; + } @action enterPressed = (e: any) => { @@ -59,14 +59,14 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> var text = e.target.value; if (text[0] === '#') { let command = text.slice(1, text.length); - this._fieldKey = new Key(command) + this._fieldKey = new Key(command); // if (command === "Title" || command === "title") { // this._fieldKey = KeyStore.Title; // } // else if (command === "Width" || command === "width") { // this._fieldKey = KeyStore.Width; // } - this._title = "changed" + this._title = "changed"; // TODO: Change field with switch statement } else { @@ -89,7 +89,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> return { x: Math.min(sptX, bounds.x), y: Math.min(sptY, bounds.y), r: Math.max(bptX, bounds.r), b: Math.max(bptY, bounds.b) - } + }; }, { x: Number.MAX_VALUE, y: Number.MAX_VALUE, r: Number.MIN_VALUE, b: Number.MIN_VALUE }); } @@ -104,7 +104,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> document.addEventListener("pointermove", this.onBackgroundMove); document.removeEventListener("pointerup", this.onBackgroundUp); document.addEventListener("pointerup", this.onBackgroundUp); - this._lastDrag = [e.clientX, e.clientY] + this._lastDrag = [e.clientX, e.clientY]; e.stopPropagation(); e.preventDefault(); } @@ -127,7 +127,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> dragComplete: action(() => this._dragging = false), }, hideSource: true - }) + }); e.stopPropagation(); } @@ -199,53 +199,53 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> onLinkerButtonDown = (e: React.PointerEvent): void => { e.stopPropagation(); - document.removeEventListener("pointermove", this.onLinkerButtonMoved) + document.removeEventListener("pointermove", this.onLinkerButtonMoved); document.addEventListener("pointermove", this.onLinkerButtonMoved); - document.removeEventListener("pointerup", this.onLinkerButtonUp) + document.removeEventListener("pointerup", this.onLinkerButtonUp); document.addEventListener("pointerup", this.onLinkerButtonUp); } onLinkerButtonUp = (e: PointerEvent): void => { - document.removeEventListener("pointermove", this.onLinkerButtonMoved) - document.removeEventListener("pointerup", this.onLinkerButtonUp) + document.removeEventListener("pointermove", this.onLinkerButtonMoved); + document.removeEventListener("pointerup", this.onLinkerButtonUp); e.stopPropagation(); } onLinkerButtonMoved = (e: PointerEvent): void => { if (this._linkerButton.current !== null) { - document.removeEventListener("pointermove", this.onLinkerButtonMoved) - document.removeEventListener("pointerup", this.onLinkerButtonUp) + document.removeEventListener("pointermove", this.onLinkerButtonMoved); + document.removeEventListener("pointerup", this.onLinkerButtonUp); let dragData = new DragManager.LinkDragData(SelectionManager.SelectedDocuments()[0]); DragManager.StartLinkDrag(this._linkerButton.current, dragData, e.pageX, e.pageY, { handlers: { dragComplete: action(() => { }), }, hideSource: false - }) + }); } e.stopPropagation(); } onLinkButtonDown = (e: React.PointerEvent): void => { e.stopPropagation(); - document.removeEventListener("pointermove", this.onLinkButtonMoved) + document.removeEventListener("pointermove", this.onLinkButtonMoved); document.addEventListener("pointermove", this.onLinkButtonMoved); - document.removeEventListener("pointerup", this.onLinkButtonUp) + document.removeEventListener("pointerup", this.onLinkButtonUp); document.addEventListener("pointerup", this.onLinkButtonUp); } onLinkButtonUp = (e: PointerEvent): void => { - document.removeEventListener("pointermove", this.onLinkButtonMoved) - document.removeEventListener("pointerup", this.onLinkButtonUp) + document.removeEventListener("pointermove", this.onLinkButtonMoved); + document.removeEventListener("pointerup", this.onLinkButtonUp); e.stopPropagation(); } onLinkButtonMoved = async (e: PointerEvent) => { if (this._linkButton.current !== null) { - document.removeEventListener("pointermove", this.onLinkButtonMoved) + document.removeEventListener("pointermove", this.onLinkButtonMoved); document.removeEventListener("pointerup", this.onLinkButtonUp); let sourceDoc = SelectionManager.SelectedDocuments()[0].props.Document; - let srcTarg = sourceDoc.GetT(KeyStore.Prototype, Document) + let srcTarg = sourceDoc.GetT(KeyStore.Prototype, Document); let draggedDocs = (srcTarg && srcTarg !== FieldWaiting) ? srcTarg.GetList(KeyStore.LinkedToDocs, [] as Document[]).map(linkDoc => (linkDoc.GetT(KeyStore.LinkedToDocs, Document)) as Document) : []; @@ -265,7 +265,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> dragComplete: action(() => { }), }, hideSource: false - }) + }); } } e.stopPropagation(); @@ -285,38 +285,38 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> case "": break; case "documentDecorations-topLeftResizer": - dX = -1 - dY = -1 - dW = -(e.movementX) - dH = -(e.movementY) + dX = -1; + dY = -1; + dW = -(e.movementX); + dH = -(e.movementY); break; case "documentDecorations-topRightResizer": - dW = e.movementX - dY = -1 - dH = -(e.movementY) + dW = e.movementX; + dY = -1; + dH = -(e.movementY); break; case "documentDecorations-topResizer": - dY = -1 - dH = -(e.movementY) + dY = -1; + dH = -(e.movementY); break; case "documentDecorations-bottomLeftResizer": - dX = -1 - dW = -(e.movementX) - dH = e.movementY + dX = -1; + dW = -(e.movementX); + dH = e.movementY; break; case "documentDecorations-bottomRightResizer": - dW = e.movementX - dH = e.movementY + dW = e.movementX; + dH = e.movementY; break; case "documentDecorations-bottomResizer": - dH = e.movementY + dH = e.movementY; break; case "documentDecorations-leftResizer": - dX = -1 - dW = -(e.movementX) + dX = -1; + dW = -(e.movementX); break; case "documentDecorations-rightResizer": - dW = e.movementX + dW = e.movementX; break; } @@ -338,14 +338,15 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> var nativeWidth = doc.GetNumber(KeyStore.NativeWidth, 0); var nativeHeight = doc.GetNumber(KeyStore.NativeHeight, 0); if (nativeWidth > 0 && nativeHeight > 0) { - if (Math.abs(dW) > Math.abs(dH)) + if (Math.abs(dW) > Math.abs(dH)) { actualdH = nativeHeight / nativeWidth * actualdW; + } else actualdW = nativeWidth / nativeHeight * actualdH; } doc.SetNumber(KeyStore.Width, actualdW); doc.SetNumber(KeyStore.Height, actualdH); } - }) + }); } onPointerUp = (e: PointerEvent): void => { @@ -362,10 +363,10 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> if (this._title === "changed" && this._documents.length > 0) { let field = this._documents[0].props.Document.Get(this._fieldKey); if (field instanceof TextField) { - return (field as TextField).GetValue(); + return (field).GetValue(); } else if (field instanceof NumberField) { - return (field as NumberField).GetValue().toString(); + return (field).GetValue().toString(); } } return this._title; @@ -388,7 +389,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> return (null); } if (isNaN(bounds.r) || isNaN(bounds.b) || isNaN(bounds.x) || isNaN(bounds.y)) { - console.log("DocumentDecorations: Bounds Error") + console.log("DocumentDecorations: Bounds Error"); return (null); } @@ -414,7 +415,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> top: bounds.y - this._resizeBorderWidth / 2, pointerEvents: this._dragging ? "none" : "all", zIndex: SelectionManager.SelectedDocuments().length > 1 ? 1000 : 0, - }} onPointerDown={this.onBackgroundDown} onContextMenu={(e: React.MouseEvent) => { e.preventDefault(); e.stopPropagation() }} > + }} onPointerDown={this.onBackgroundDown} onContextMenu={(e: React.MouseEvent) => { e.preventDefault(); e.stopPropagation(); }} >
∞
- ) + ); } } \ No newline at end of file diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx index 982aacdea..2f17c6c51 100644 --- a/src/client/views/EditableView.tsx +++ b/src/client/views/EditableView.tsx @@ -1,7 +1,7 @@ -import React = require('react') +import React = require('react'); import { observer } from 'mobx-react'; import { observable, action, trace } from 'mobx'; -import "./EditableView.scss" +import "./EditableView.scss"; export interface EditableProps { /** @@ -22,7 +22,7 @@ export interface EditableProps { * The contents to render when not editing */ contents: any; - height: number + height: number; display?: string; } @@ -55,14 +55,14 @@ export class EditableView extends React.Component { render() { if (this.editing) { return this.editing = false)} - style={{ display: this.props.display }}> + style={{ display: this.props.display }}>; } else { return (
this.editing = true)} > {this.props.contents}
- ) + ); } } } \ No newline at end of file diff --git a/src/client/views/InkingCanvas.tsx b/src/client/views/InkingCanvas.tsx index 4ecc44119..47ee8eb85 100644 --- a/src/client/views/InkingCanvas.tsx +++ b/src/client/views/InkingCanvas.tsx @@ -82,7 +82,7 @@ export class InkingCanvas extends React.Component { }); this.inkData = data; } - }; + } @action onPointerUp = (e: PointerEvent): void => { @@ -109,7 +109,7 @@ export class InkingCanvas extends React.Component { @action onPointerMove = (e: PointerEvent): void => { - e.stopPropagation() + e.stopPropagation(); e.preventDefault(); if (InkingControl.Instance.selectedTool !== InkTool.Eraser) { let data = this.inkData; // add points to new line as it is being drawn @@ -120,7 +120,7 @@ export class InkingCanvas extends React.Component { } this.inkData = data; } - }; + } relativeCoordinatesForEvent = (ex: number, ey: number): { x: number, y: number } => { let [x, y] = this.props.getScreenTransform().transformPoint(ex, ey); @@ -137,14 +137,15 @@ export class InkingCanvas extends React.Component { @computed get drawnPaths() { - let curPage = this.props.Document.GetNumber(KeyStore.CurPage, -1) + let curPage = this.props.Document.GetNumber(KeyStore.CurPage, -1); let paths = Array.from(this.inkData).reduce((paths, [id, strokeData]) => { - if (strokeData.page === -1 || strokeData.page === curPage) + if (strokeData.page === -1 || strokeData.page === curPage) { paths.push() + tool={strokeData.tool} deleteCallback={this.removeLine} />); + } return paths; }, [] as JSX.Element[]); return [ { {this.props.children()} {this.drawnPaths}
- ) + ); } } \ No newline at end of file diff --git a/src/client/views/InkingControl.tsx b/src/client/views/InkingControl.tsx index 64ee66ec7..9a68f0671 100644 --- a/src/client/views/InkingControl.tsx +++ b/src/client/views/InkingControl.tsx @@ -1,10 +1,10 @@ import { observable, action, computed } from "mobx"; -import { CirclePicker, ColorResult } from 'react-color' +import { CirclePicker, ColorResult } from 'react-color'; import React = require("react"); import { InkTool } from "../../fields/InkField"; import { observer } from "mobx-react"; -import "./InkingControl.scss" +import "./InkingControl.scss"; import { library } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faPen, faHighlighter, faEraser, faBan } from '@fortawesome/free-solid-svg-icons'; @@ -25,7 +25,7 @@ export class InkingControl extends React.Component { constructor(props: Readonly<{}>) { super(props); - InkingControl.Instance = this + InkingControl.Instance = this; } @action @@ -66,9 +66,9 @@ export class InkingControl extends React.Component { selected = (tool: InkTool) => { if (this._selectedTool === tool) { - return { color: "#61aaa3" } + return { color: "#61aaa3" }; } - return {} + return {}; } @action @@ -111,6 +111,6 @@ export class InkingControl extends React.Component { onChange={(e: React.ChangeEvent) => this.switchWidth(e.target.value)} /> - ) + ); } } \ No newline at end of file diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index 12b15a3f0..0f05da22c 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -30,7 +30,7 @@ export class InkingStroke extends React.Component { } parseData = (line: Array<{ x: number, y: number }>): string => { - return !line.length ? "" : "M " + line.map(p => (p.x + this.props.offsetX) + " " + (p.y + this.props.offsetY)).join(" L ") + return !line.length ? "" : "M " + line.map(p => (p.x + this.props.offsetX) + " " + (p.y + this.props.offsetY)).join(" L "); } createStyle() { @@ -41,7 +41,7 @@ export class InkingStroke extends React.Component { fill: "none", stroke: this._strokeColor, strokeWidth: this._strokeWidth + "px", - } + }; } } @@ -53,6 +53,6 @@ export class InkingStroke extends React.Component { return ( - ) + ); } } \ No newline at end of file diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index 6376fd694..fd2e23c91 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -16,7 +16,7 @@ import { WorkspacesMenu } from '../../server/authentication/controllers/Workspac import { CurrentUserUtils } from '../../server/authentication/models/current_user_utils'; import { MessageStore } from '../../server/Message'; import { Utils, returnTrue, emptyFunction } from '../../Utils'; -import * as rp from 'request-promise' +import * as rp from 'request-promise'; import { RouteStore } from '../../server/RouteStore'; import { ServerUtils } from '../../server/ServerUtil'; import { Documents } from '../documents/Documents'; @@ -74,7 +74,7 @@ export class Main extends React.Component { if (pathname.length > 1 && pathname[pathname.length - 2] === 'doc') { CurrentUserUtils.MainDocId = pathname[pathname.length - 1]; } - }; + } CurrentUserUtils.loadCurrentUser(); @@ -119,8 +119,8 @@ export class Main extends React.Component { initEventListeners = () => { // window.addEventListener("pointermove", (e) => this.reportLocation(e)) - window.addEventListener("drop", (e) => e.preventDefault(), false) // drop event handler - window.addEventListener("dragover", (e) => e.preventDefault(), false) // drag event handler + window.addEventListener("drop", (e) => e.preventDefault(), false); // drop event handler + window.addEventListener("dragover", (e) => e.preventDefault(), false); // drag event handler // click interactions for the context menu document.addEventListener("pointerdown", action(function (e: PointerEvent) { if (!ContextMenu.Instance.intersects(e.pageX, e.pageY)) { @@ -139,15 +139,15 @@ export class Main extends React.Component { } else { this.createNewWorkspace(); } - }) + }); } else { Server.GetField(CurrentUserUtils.MainDocId).then(field => { if (field instanceof Document) { - this.openWorkspace(field) + this.openWorkspace(field); } else { this.createNewWorkspace(CurrentUserUtils.MainDocId); } - }) + }); } } @@ -163,7 +163,7 @@ export class Main extends React.Component { // bcz: strangely, we need a timeout to prevent exceptions/issues initializing GoldenLayout (the rendering engine for Main Container) setTimeout(() => { this.openWorkspace(mainDoc); - let pendingDocument = Documents.SchemaDocument([], { title: "New Mobile Uploads" }) + let pendingDocument = Documents.SchemaDocument([], { title: "New Mobile Uploads" }); mainDoc.Set(KeyStore.OptionalRightCollection, pendingDocument); }, 0); } @@ -182,7 +182,7 @@ export class Main extends React.Component { if (f && f.Data.length > 0) { CollectionDockingView.Instance.AddRightSplit(col); } - }) + }); } }, 100); }); @@ -191,7 +191,7 @@ export class Main extends React.Component { @observable workspacesShown: boolean = false; - areWorkspacesShown = () => this.workspacesShown + areWorkspacesShown = () => this.workspacesShown; @action toggleWorkspaces = () => { this.workspacesShown = !this.workspacesShown; @@ -199,7 +199,7 @@ export class Main extends React.Component { pwidthFunc = () => this.pwidth; pheightFunc = () => this.pheight; - focusDocument = (doc: Document) => { } + focusDocument = (doc: Document) => { }; noScaling = () => 1; @observable _textDoc?: Document = undefined; @@ -208,8 +208,9 @@ export class Main extends React.Component { SetTextDoc(textDoc?: Document, div?: HTMLDivElement) { this._textDoc = undefined; this._textDoc = textDoc; - if (div) + if (div) { this._textRect = div.getBoundingClientRect(); + } } @computed @@ -221,7 +222,7 @@ export class Main extends React.Component { let h: number = this._textRect.height; return
{ }} /> - + ; } else return (null); } @@ -241,19 +242,19 @@ export class Main extends React.Component { focus={this.focusDocument} parentActive={returnTrue} onActiveChanged={emptyFunction} - ContainingCollectionView={undefined} /> + ContainingCollectionView={undefined} />; } /* for the expandable add nodes menu. Not included with the miscbuttons because once it expands it expands the whole div with it, making canvas interactions limited. */ @computed get nodesMenu() { let imgurl = "https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg"; - let pdfurl = "http://www.adobe.com/support/products/enterprise/knowledgecenter/media/c4611_sample_explain.pdf" + let pdfurl = "http://www.adobe.com/support/products/enterprise/knowledgecenter/media/c4611_sample_explain.pdf"; let weburl = "https://cs.brown.edu/courses/cs166/"; let audiourl = "http://techslides.com/demos/samples/sample.mp3"; let videourl = "http://techslides.com/demos/sample-videos/small.mp4"; - let addTextNode = action(() => Documents.TextDocument({ width: 200, height: 200, title: "a text note" })) + 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._northstarSchemas, { width: 250, height: 400, title: "northstar schemas", copyDraggedItems: true })); @@ -261,7 +262,7 @@ export class Main extends React.Component { 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" })); let addWebNode = action(() => Documents.WebDocument(weburl, { width: 200, height: 200, title: "a sample web page" })); - let addAudioNode = action(() => Documents.AudioDocument(audiourl, { width: 200, height: 200, title: "audio node" })) + let addAudioNode = action(() => Documents.AudioDocument(audiourl, { width: 200, height: 200, title: "audio node" })); let btns: [React.RefObject, IconName, string, () => Document][] = [ [React.createRef(), "font", "Add Textbox", addTextNode], @@ -273,7 +274,7 @@ export class Main extends React.Component { [React.createRef(), "object-group", "Add Collection", addColNode], [React.createRef(), "tree", "Add Tree", addTreeNode], [React.createRef(), "table", "Add Schema", addSchemaNode], - ] + ]; return < div id="add-nodes-menu" > @@ -289,7 +290,7 @@ export class Main extends React.Component {
)}
-
+
; } /* @TODO this should really be moved into a moveable toolbar component, but for now let's put it here to meet the deadline */ @@ -298,7 +299,7 @@ export class Main extends React.Component { let workspacesRef = React.createRef(); let logoutRef = React.createRef(); - let clearDatabase = action(() => Utils.Emit(Server.Socket, MessageStore.DeleteAll, {})) + let clearDatabase = action(() => Utils.Emit(Server.Socket, MessageStore.DeleteAll, {})); return [ ,
@@ -310,7 +311,7 @@ export class Main extends React.Component {
,
- ] + ]; } render() { @@ -318,7 +319,7 @@ export class Main extends React.Component { let workspaces = this.userDocument.GetT>(KeyStore.Workspaces, ListField); if (workspaces && workspaces !== FieldWaiting) { workspaceMenu = + isShown={this.areWorkspacesShown} toggle={this.toggleWorkspaces} />; } return ( <> @@ -359,7 +360,7 @@ export class Main extends React.Component { schemaDocuments.push(field); } else { var atmod = new ColumnAttributeModel(attr); - let histoOp = new HistogramOperation(schema!.displayName!, + let histoOp = new HistogramOperation(schema.displayName!, new AttributeTransformationModel(atmod, AggregateFunction.None), new AttributeTransformationModel(atmod, AggregateFunction.Count), new AttributeTransformationModel(atmod, AggregateFunction.Count)); @@ -368,7 +369,7 @@ export class Main extends React.Component { })); }); return schemaDoc; - }) + }); } } async initializeNorthstar(): Promise { @@ -386,7 +387,7 @@ export class Main extends React.Component { } (async () => { - await Documents.initProtos() - await CurrentUserUtils.loadCurrentUser() + await Documents.initProtos(); + await CurrentUserUtils.loadCurrentUser(); ReactDOM.render(
, document.getElementById('root')); -})() +})(); diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx index 7a5ab6e3c..32462a4c1 100644 --- a/src/client/views/collections/CollectionBaseView.tsx +++ b/src/client/views/collections/CollectionBaseView.tsx @@ -66,17 +66,20 @@ export class CollectionBaseView extends React.Component { createsCycle(documentToAdd: Document, containerDocument: Document): boolean { let data = documentToAdd.GetList(KeyStore.Data, []); for (const doc of data) { - if (this.createsCycle(doc, containerDocument)) + if (this.createsCycle(doc, containerDocument)) { return true; + } } let annots = documentToAdd.GetList(KeyStore.Annotations, []); for (const annot of annots) { - if (this.createsCycle(annot, containerDocument)) + if (this.createsCycle(annot, containerDocument)) { return true; + } } for (let containerProto: FieldValue = containerDocument; containerProto && containerProto !== FieldWaiting; containerProto = containerProto.GetPrototype()) { - if (containerProto.Id === documentToAdd.Id) + if (containerProto.Id === documentToAdd.Id) { return true; + } } return false; } @@ -91,20 +94,23 @@ export class CollectionBaseView extends React.Component { } if (props.Document.Get(props.fieldKey) instanceof Field) { //TODO This won't create the field if it doesn't already exist - const value = props.Document.GetData(props.fieldKey, ListField, new Array()) + const value = props.Document.GetData(props.fieldKey, ListField, new Array()); if (!this.createsCycle(doc, props.Document)) { - if (!value.some(v => v.Id === doc.Id) || allowDuplicates) + if (!value.some(v => v.Id === doc.Id) || allowDuplicates) { value.push(doc); + } } - else + else { return false; + } } else { let proto = props.Document.GetPrototype(); if (!proto || proto === FieldWaiting || !this.createsCycle(proto, doc)) { props.Document.SetOnPrototype(props.fieldKey, new ListField([doc])); } - else + else { return false; + } } return true; } @@ -113,7 +119,7 @@ export class CollectionBaseView extends React.Component { removeDocument(doc: Document): boolean { const props = this.props; //TODO This won't create the field if it doesn't already exist - const value = props.Document.GetData(props.fieldKey, ListField, new Array()) + const value = props.Document.GetData(props.fieldKey, ListField, new Array()); let index = -1; for (let i = 0; i < value.length; i++) { if (value[i].Id === doc.Id) { @@ -125,16 +131,16 @@ export class CollectionBaseView extends React.Component { if (annotationOn === props.Document) { doc.Set(KeyStore.AnnotationOn, undefined, true); } - }) + }); if (index !== -1) { - value.splice(index, 1) + value.splice(index, 1); // SelectionManager.DeselectAll() - ContextMenu.Instance.clearItems() + ContextMenu.Instance.clearItems(); return true; } - return false + return false; } @action.bound @@ -155,12 +161,12 @@ export class CollectionBaseView extends React.Component { moveDocument: this.moveDocument, active: this.active, onActiveChanged: this.onActiveChanged, - } + }; return (
{this.props.children(this.collectionViewType, props)}
- ) + ); } } \ No newline at end of file diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index c3757a377..ea6d3a247 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -32,7 +32,7 @@ export class CollectionDockingView extends React.Component) => { - if (f instanceof Document) - DragManager.StartDocumentDrag([tab], new DragManager.DocumentDragData([f as Document]), e.pageX, e.pageY, + if (f instanceof Document) { + DragManager.StartDocumentDrag([tab], new DragManager.DocumentDragData([f]), e.pageX, e.pageY, { handlers: { dragComplete: action(() => { }), }, hideSource: false - }) + }); + } })); } if (className === "lm_drag_handle" || className === "lm_close" || className === "lm_maximise" || className === "lm_minimise" || className === "lm_close_tab") { @@ -220,7 +222,7 @@ export class CollectionDockingView extends React.Component { var json = JSON.stringify(this._goldenLayout.toConfig()); - this.props.Document.SetText(KeyStore.Data, json) + this.props.Document.SetText(KeyStore.Data, json); } itemDropped = () => { @@ -236,7 +238,7 @@ export class CollectionDockingView extends React.Component { Server.GetField(this.props.documentId, action((f: Opt) => this._document = f as Document)); } - private _nativeWidth = () => this._document!.GetNumber(KeyStore.NativeWidth, this._panelWidth) - private _nativeHeight = () => this._document!.GetNumber(KeyStore.NativeHeight, this._panelHeight) - private _contentScaling = () => this._panelWidth / (this._nativeWidth() ? this._nativeWidth() : this._panelWidth) + private _nativeWidth = () => this._document!.GetNumber(KeyStore.NativeWidth, this._panelWidth); + private _nativeHeight = () => this._document!.GetNumber(KeyStore.NativeHeight, this._panelHeight); + private _contentScaling = () => this._panelWidth / (this._nativeWidth() ? this._nativeWidth() : this._panelWidth); ScreenToLocalTransform = () => { let { scale, translateX, translateY } = Utils.GetScreenTransform(this._mainCont.current!); - return CollectionDockingView.Instance.props.ScreenToLocalTransform().translate(-translateX, -translateY).scale(scale / this._contentScaling()) + return CollectionDockingView.Instance.props.ScreenToLocalTransform().translate(-translateX, -translateY).scale(scale / this._contentScaling()); } render() { - if (!this._document) + if (!this._document) { return (null); + } var content =
{ onActiveChanged={emptyFunction} focus={(doc: Document) => { }} ContainingCollectionView={undefined} /> -
+
; return { this._panelWidth = r.entry.width; this._panelHeight = r.entry.height; })}> {({ measureRef }) =>
{content}
} -
+ ; } } \ No newline at end of file diff --git a/src/client/views/collections/CollectionPDFView.tsx b/src/client/views/collections/CollectionPDFView.tsx index 32f50afc0..97bac745c 100644 --- a/src/client/views/collections/CollectionPDFView.tsx +++ b/src/client/views/collections/CollectionPDFView.tsx @@ -2,7 +2,7 @@ import { action, computed, observable } from "mobx"; import { observer } from "mobx-react"; import { KeyStore } from "../../../fields/KeyStore"; import { ContextMenu } from "../ContextMenu"; -import "./CollectionPDFView.scss" +import "./CollectionPDFView.scss"; import React = require("react"); import { CollectionFreeFormView } from "./collectionFreeForm/CollectionFreeFormView"; import { FieldView, FieldViewProps } from "../nodes/FieldView"; @@ -44,7 +44,7 @@ export class CollectionPDFView extends React.Component { {this.props.isSelected() ? this.uIButtons : (null)} - ) + ); } render() { @@ -52,6 +52,6 @@ export class CollectionPDFView extends React.Component { {this.subView} - ) + ); } } \ No newline at end of file diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index 9b780f29b..52933818f 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -1,4 +1,4 @@ -import React = require("react") +import React = require("react"); import { library } from '@fortawesome/fontawesome-svg-core'; import { faCog, faPlus } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; @@ -41,7 +41,7 @@ class KeyToggle extends React.Component<{ keyId: string, checked: boolean, toggl if (field instanceof Key) { this.key = field; } - })) + })); } render() { @@ -49,7 +49,7 @@ class KeyToggle extends React.Component<{ keyId: string, checked: boolean, toggl return (
this.key && this.props.toggle(this.key)} /> {this.key.Name} -
) +
); } return (null); } @@ -85,10 +85,10 @@ export class CollectionSchemaView extends CollectionSubView { focus: emptyFunction, active: returnFalse, onActiveChanged: emptyFunction, - } + }; let contents = ( - ) + ); let reference = React.createRef(); let onItemDown = setupDrag(reference, () => props.Document, this.props.moveDocument); let applyToDoc = (doc: Document, run: (args?: { [name: string]: any }) => any) => { @@ -106,7 +106,7 @@ export class CollectionSchemaView extends CollectionSubView { } } return false; - } + }; return (
applyToDoc(doc, run)); } - }) + }); }}>
- ) + ); } private getTrProps: ComponentPropsGetterR = (state, rowInfo) => { @@ -156,7 +156,7 @@ export class CollectionSchemaView extends CollectionSubView { that._selectedIndex = rowInfo.index; if (handleOriginal) { - handleOriginal() + handleOriginal(); } }), style: { @@ -182,7 +182,7 @@ export class CollectionSchemaView extends CollectionSubView { this.columns.splice(index, 1); } - }) + }); } //toggles preview side-panel of schema @@ -197,7 +197,7 @@ export class CollectionSchemaView extends CollectionSubView { @computed get findAllDocumentKeys(): { [id: string]: boolean } { const docs = this.props.Document.GetList(this.props.fieldKey, []); - let keys: { [id: string]: boolean } = {} + let keys: { [id: string]: boolean } = {}; if (this._optionsActivated > -1) { // bcz: ugh. this is untracked since otherwise a large collection of documents will blast the server for all their fields. // then as each document's fields come back, we update the documents _proxies. Each time we do this, the whole schema will be @@ -206,7 +206,7 @@ export class CollectionSchemaView extends CollectionSubView { // is displayed (unlikely) it won't show up until something else changes. untracked(() => docs.map(doc => doc.GetAllPrototypes().map(proto => proto._proxies.forEach((val: any, key: string) => keys[key] = false)))); } - this.columns.forEach(key => keys[key.Id] = true) + this.columns.forEach(key => keys[key.Id] = true); return keys; } @@ -248,10 +248,10 @@ export class CollectionSchemaView extends CollectionSubView { getContentScaling = (): number => this._contentScaling; getPanelWidth = (): number => this._panelWidth; getPanelHeight = (): number => this._panelHeight; - getTransform = (): Transform => this.props.ScreenToLocalTransform().translate(- COLLECTION_BORDER_WIDTH - this.DIVIDER_WIDTH - this._dividerX, - COLLECTION_BORDER_WIDTH).scale(1 / this._contentScaling) - getPreviewTransform = (): Transform => this.props.ScreenToLocalTransform().translate(- COLLECTION_BORDER_WIDTH - this.DIVIDER_WIDTH - this._dividerX - this._tableWidth, - COLLECTION_BORDER_WIDTH).scale(1 / this._contentScaling) + getTransform = (): Transform => this.props.ScreenToLocalTransform().translate(- COLLECTION_BORDER_WIDTH - this.DIVIDER_WIDTH - this._dividerX, - COLLECTION_BORDER_WIDTH).scale(1 / this._contentScaling); + getPreviewTransform = (): Transform => this.props.ScreenToLocalTransform().translate(- COLLECTION_BORDER_WIDTH - this.DIVIDER_WIDTH - this._dividerX - this._tableWidth, - COLLECTION_BORDER_WIDTH).scale(1 / this._contentScaling); - focusDocument = (doc: Document) => { } + focusDocument = (doc: Document) => { }; onPointerDown = (e: React.PointerEvent): void => { if (this.props.isSelected()) { @@ -273,8 +273,9 @@ export class CollectionSchemaView extends CollectionSubView { this.newKeyName = e.currentTarget.value; } onWheel = (e: React.WheelEvent): void => { - if (this.props.active()) + if (this.props.active()) { e.stopPropagation(); + } } @observable _optionsActivated: number = 0; @@ -322,9 +323,9 @@ export class CollectionSchemaView extends CollectionSubView {
} - ) + ); let dividerDragger = this.splitPercentage === 0 ? (null) : -
+
; //options button and menu let optionsMenu = !this.props.active() ? (null) : (
- ) + ); } } \ No newline at end of file diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 59b89e119..bd385c27e 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -14,7 +14,7 @@ import { NumberField } from "../../../fields/NumberField"; import { ServerUtils } from "../../../server/ServerUtil"; import { Server } from "../../Server"; import { FieldViewProps } from "../nodes/FieldView"; -import * as rp from 'request-promise' +import * as rp from 'request-promise'; export interface CollectionViewProps extends FieldViewProps { addDocument: (document: Document, allowDuplicates?: boolean) => boolean; @@ -58,8 +58,8 @@ export class CollectionSubView extends React.Component { let entry = new TupleField<[string, string], [number, number]>([textInfo, position]); cursors.push(entry); } - })) - }) + })); + }); } } @@ -77,17 +77,17 @@ export class CollectionSubView extends React.Component { added = de.data.droppedDocuments.reduce((added: boolean, d) => added || this.props.addDocument(d), false); } else if (de.data.moveDocument) { const move = de.data.moveDocument; - added = de.data.droppedDocuments.reduce((added: boolean, d) => added || move(d, this.props.Document, this.props.addDocument), false) + added = de.data.droppedDocuments.reduce((added: boolean, d) => added || move(d, this.props.Document, this.props.addDocument), false); } else { - added = de.data.droppedDocuments.reduce((added: boolean, d) => added || this.props.addDocument(d), false) + added = de.data.droppedDocuments.reduce((added: boolean, d) => added || this.props.addDocument(d), false); } e.stopPropagation(); return added; } if (de.data instanceof DragManager.LinkDragData) { let sourceDoc: Document = de.data.linkSourceDocumentView.props.Document; - if (sourceDoc) runInAction(() => { - let srcTarg = sourceDoc.GetT(KeyStore.Prototype, Document) + if (sourceDoc) { runInAction(() => { + let srcTarg = sourceDoc.GetT(KeyStore.Prototype, Document); if (srcTarg && srcTarg !== FieldWaiting) { let linkDocs = srcTarg.GetList(KeyStore.LinkedToDocs, [] as Document[]); linkDocs.map(linkDoc => { @@ -97,9 +97,10 @@ export class CollectionSubView extends React.Component { de.data.droppedDocuments.push(dropdoc); this.props.addDocument(dropdoc, false); } - }) + }); } - }) + }); + } return true; } return false; @@ -133,7 +134,7 @@ export class CollectionSubView extends React.Component { alias.SetNumber(KeyStore.Height, options.height || options.width || 300); this.props.addDocument(alias, false); } - }) + }); return undefined; } ctor = Documents.WebDocument; @@ -151,8 +152,8 @@ export class CollectionSubView extends React.Component { if (text && text.startsWith(" { let prom = new Promise(res => e.dataTransfer.items[i].getAsString(res)).then(action((s: string) => { str = s; - return rp.head(ServerUtils.prepend(RouteStore.corsProxy + "/" + s)) + return rp.head(ServerUtils.prepend(RouteStore.corsProxy + "/" + s)); })).then(res => { let type = res.headers["content-type"]; if (type) { - let doc = this.getDocumentFromType(type, str, { ...options, width: 300, nativeWidth: 300 }) + let doc = this.getDocumentFromType(type, str, { ...options, width: 300, nativeWidth: 300 }); if (doc) { this.props.addDocument(doc, false); } @@ -186,13 +187,13 @@ export class CollectionSubView extends React.Component { promises.push(prom); // this.props.addDocument(Documents.WebDocument(s, { ...options, width: 300, height: 300 }), false) } - let type = item.type + let type = item.type; if (item.kind === "file") { let file = item.getAsFile(); - let formData = new FormData() + let formData = new FormData(); if (file) { - formData.append('file', file) + formData.append('file', file); } let prom = fetch(upload, { @@ -201,15 +202,15 @@ export class CollectionSubView extends React.Component { }).then(async (res: Response) => { const json = await res.json(); json.map((file: any) => { - let path = window.location.origin + file + let path = window.location.origin + file; runInAction(() => { - let doc = this.getDocumentFromType(type, path, { ...options, nativeWidth: 300, width: 300 }) + let doc = this.getDocumentFromType(type, path, { ...options, nativeWidth: 300, width: 300 }); let docs = this.props.Document.GetT(KeyStore.Data, ListField); if (docs !== FieldWaiting) { if (!docs) { docs = new ListField(); - this.props.Document.Set(KeyStore.Data, docs) + this.props.Document.Set(KeyStore.Data, docs); } if (doc) { docs.Data.push(doc); diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 2bdf0baa6..659cff9fe 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -12,7 +12,7 @@ import { EditableView } from "../EditableView"; import "./CollectionTreeView.scss"; import { CollectionView } from "./CollectionView"; import { CollectionSubView } from "./CollectionSubView"; -import React = require("react") +import React = require("react"); import { COLLECTION_BORDER_WIDTH } from './CollectionBaseView'; import { props } from 'bluebird'; @@ -58,7 +58,7 @@ class TreeView extends React.Component { return true; } //TODO This should check if it was removed - this.remove(document) + this.remove(document); return addDoc(document); } @@ -69,7 +69,7 @@ class TreeView extends React.Component { case BulletType.Collapsed: bullet = "caret-right"; break; case BulletType.Collapsible: bullet = "caret-down"; break; } - return
{bullet ? : ""}
+ return
{bullet ? : ""}
; } /** @@ -93,7 +93,7 @@ class TreeView extends React.Component {
{editableView(this.props.document.Title)}
-
) +
); } render() { @@ -105,7 +105,7 @@ class TreeView extends React.Component { bulletType = BulletType.Collapsible; childElements =
    {children.Data.map(value => )} -
+ ; } else bulletType = BulletType.Collapsed; } @@ -115,7 +115,7 @@ class TreeView extends React.Component { {this.renderTitle()} {childElements ? childElements : (null)} -
+
; } } @@ -136,7 +136,7 @@ export class CollectionTreeView extends CollectionSubView { let childrenElement = !children || children === FieldWaiting ? (null) : (children.Data.map(value => ) - ) + ); return (
e.stopPropagation()} onDrop={(e: React.DragEvent) => this.onDrop(e, {})} ref={this.createDropTarget} style={{ borderWidth: `${COLLECTION_BORDER_WIDTH}px` }}> diff --git a/src/client/views/collections/CollectionVideoView.tsx b/src/client/views/collections/CollectionVideoView.tsx index 1acc76c85..b02983a2e 100644 --- a/src/client/views/collections/CollectionVideoView.tsx +++ b/src/client/views/collections/CollectionVideoView.tsx @@ -4,7 +4,7 @@ import { KeyStore } from "../../../fields/KeyStore"; import { ContextMenu } from "../ContextMenu"; import { CollectionViewType, CollectionBaseView, CollectionRenderProps } from "./CollectionBaseView"; import React = require("react"); -import "./CollectionVideoView.scss" +import "./CollectionVideoView.scss"; import { CollectionFreeFormView } from "./collectionFreeForm/CollectionFreeFormView"; import { FieldView, FieldViewProps } from "../nodes/FieldView"; @@ -111,7 +111,7 @@ export class CollectionVideoView extends React.Component { {this.props.isSelected() ? this.uIButtons : (null)} - ) + ); } render() { @@ -119,6 +119,6 @@ export class CollectionVideoView extends React.Component { return ( {this.subView} - ) + ); } } \ No newline at end of file diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index b31dcc888..8abd0a02d 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -1,4 +1,4 @@ -import * as React from 'react' +import * as React from 'react'; import { FieldViewProps, FieldView } from '../nodes/FieldView'; import { CollectionBaseView, CollectionViewType, CollectionRenderProps } from './CollectionBaseView'; import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView'; @@ -13,26 +13,26 @@ import { undoBatch } from '../../util/UndoManager'; @observer export class CollectionView extends React.Component { - public static LayoutString(fieldStr: string = "DataKey") { return FieldView.LayoutString(CollectionView, fieldStr) } + public static LayoutString(fieldStr: string = "DataKey") { return FieldView.LayoutString(CollectionView, fieldStr); } private SubView = (type: CollectionViewType, renderProps: CollectionRenderProps) => { let props = { ...this.props, ...renderProps }; switch (type) { - case CollectionViewType.Schema: return () - case CollectionViewType.Docking: return () - case CollectionViewType.Tree: return () + case CollectionViewType.Schema: return (); + case CollectionViewType.Docking: return (); + case CollectionViewType.Tree: return (); case CollectionViewType.Freeform: default: - return () + return (); } return (null); } onContextMenu = (e: React.MouseEvent): void => { if (!e.isPropagationStopped() && this.props.Document.Id !== CurrentUserUtils.MainDocId) { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 - ContextMenu.Instance.addItem({ description: "Freeform", event: undoBatch(() => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Freeform)) }) - ContextMenu.Instance.addItem({ description: "Schema", event: undoBatch(() => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Schema)) }) - ContextMenu.Instance.addItem({ description: "Treeview", event: undoBatch(() => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Tree)) }) + ContextMenu.Instance.addItem({ description: "Freeform", event: undoBatch(() => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Freeform)) }); + ContextMenu.Instance.addItem({ description: "Schema", event: undoBatch(() => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Schema)) }); + ContextMenu.Instance.addItem({ description: "Treeview", event: undoBatch(() => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Tree)) }); } } @@ -41,6 +41,6 @@ export class CollectionView extends React.Component { {this.SubView} - ) + ); } } \ No newline at end of file diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx index 3dfd74ec8..081b3eb6c 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx @@ -32,6 +32,6 @@ export class CollectionFreeFormLinkView extends React.Component - ) + ); } } \ No newline at end of file diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx index c288e7abf..cf058090d 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx @@ -17,7 +17,7 @@ export class CollectionFreeFormLinksView extends React.Component DocumentManager.Instance.getAllDocumentViews(this.HackToAvoidReactionFiringUnnecessarily!). map(dv => dv.props.Document.GetNumber(KeyStore.X, 0)), @@ -31,13 +31,14 @@ export class CollectionFreeFormLinksView extends React.Component) => field.Data.findIndex(brush => { let bdocs = brush ? brush.GetList(KeyStore.BrushingDocs, [] as Document[]) : []; - return (bdocs.length && ((bdocs[0] === dstTarg && bdocs[1] === srcTarg)) ? true : false) + return (bdocs.length && ((bdocs[0] === dstTarg && bdocs[1] === srcTarg)) ? true : false); }); let brushAction = (field: ListField) => { let found = findBrush(field); @@ -64,13 +65,13 @@ export class CollectionFreeFormLinksView extends React.Component sv.props.ContainingCollectionView && sv.props.ContainingCollectionView.props.Document === this.props.Document); } @@ -86,15 +87,16 @@ export class CollectionFreeFormLinksView extends React.Component { let match = (possiblePair.a === drawnPair.a && possiblePair.b === drawnPair.b); if (match) { - if (!drawnPair.l.reduce((found, link) => found || link.Id === connection.l.Id, false)) + if (!drawnPair.l.reduce((found, link) => found || link.Id === connection.l.Id, false)) { drawnPair.l.push(connection.l); + } } return match || found; }, false)) { drawnPairs.push({ a: possiblePair.a, b: possiblePair.b, l: [connection.l] }); } - }) - return drawnPairs + }); + return drawnPairs; }, [] as { a: Document, b: Document, l: Document[] }[]); return connections.map(c => ); } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx index 17656e4ae..fc832264d 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx @@ -57,7 +57,7 @@ export class CollectionFreeFormRemoteCursors extends React.Component { if (el) this.crosshairs = el }} + ref={(el) => { if (el) this.crosshairs = el; }} width={20} height={20} style={{ @@ -93,7 +93,7 @@ export class CollectionFreeFormRemoteCursors extends React.Component ); } - }) + }); } render() { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 1c3899b24..e694bc7a7 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -49,7 +49,7 @@ export class CollectionFreeFormView extends CollectionSubView { if (dv) { SelectionManager.SelectDoc(dv, true); } - }) + }); } public getActiveDocuments = () => { @@ -70,8 +70,8 @@ export class CollectionFreeFormView extends CollectionSubView { private outerElement?: HTMLDivElement; - @computed get panX(): number { return this.props.Document.GetNumber(KeyStore.PanX, 0) } - @computed get panY(): number { return this.props.Document.GetNumber(KeyStore.PanY, 0) } + @computed get panX(): number { return this.props.Document.GetNumber(KeyStore.PanX, 0); } + @computed get panY(): number { return this.props.Document.GetNumber(KeyStore.PanY, 0); } @computed get scale(): number { return this.props.Document.GetNumber(KeyStore.Scale, 1); } @computed get isAnnotationOverlay() { return this.props.fieldKey && this.props.fieldKey.Id === KeyStore.Annotations.Id; } // bcz: ? Why do we need to compare Id's? @computed get nativeWidth() { return this.props.Document.GetNumber(KeyStore.NativeWidth, 0); } @@ -109,7 +109,7 @@ export class CollectionFreeFormView extends CollectionSubView { d.SetNumber(KeyStore.Height, 300); } this.bringToFront(d); - }) + }); } } return true; @@ -133,8 +133,9 @@ export class CollectionFreeFormView extends CollectionSubView { document.addEventListener("pointerup", this.onPointerUp); this._lastX = this.DownX = e.pageX; this._lastY = this.DownY = e.pageY; - if (this.props.isSelected()) + if (this.props.isSelected()) { e.stopPropagation(); + } } } @@ -182,12 +183,13 @@ export class CollectionFreeFormView extends CollectionSubView { let transform = this.getTransform(); let deltaScale = (1 - (e.deltaY / coefficient)); - if (deltaScale * this.zoomScaling < 1 && this.isAnnotationOverlay) + if (deltaScale * this.zoomScaling < 1 && this.isAnnotationOverlay) { deltaScale = 1 / this.zoomScaling; + } let [x, y] = transform.transformPoint(e.clientX, e.clientY); - let localTransform = this.getLocalTransform() - localTransform = localTransform.inverse().scaleAbout(deltaScale, x, y) + let localTransform = this.getLocalTransform(); + localTransform = localTransform.inverse().scaleAbout(deltaScale, x, y); // console.log(localTransform) this.props.Document.SetNumber(KeyStore.Scale, localTransform.Scale); @@ -209,7 +211,7 @@ export class CollectionFreeFormView extends CollectionSubView { onDrop = (e: React.DragEvent): void => { var pt = this.getTransform().transformPoint(e.pageX, e.pageY); super.onDrop(e, { x: pt[0], y: pt[1] }); - }; + } onDragOver = (): void => { } @@ -228,7 +230,7 @@ export class CollectionFreeFormView extends CollectionSubView { } return doc1.GetNumber(KeyStore.ZIndex, 0) - doc2.GetNumber(KeyStore.ZIndex, 0); }).map((doc, index) => { - doc.SetNumber(KeyStore.ZIndex, index + 1) + doc.SetNumber(KeyStore.ZIndex, index + 1); }); } @@ -268,7 +270,7 @@ export class CollectionFreeFormView extends CollectionSubView { focus: this.focusDocument, parentActive: this.props.active, onActiveChanged: this.props.active, - } + }; } @computed @@ -276,10 +278,11 @@ export class CollectionFreeFormView extends CollectionSubView { var curPage = this.props.Document.GetNumber(KeyStore.CurPage, -1); return this.props.Document.GetList(this.props.fieldKey, [] as Document[]).filter(doc => doc).reduce((prev, doc) => { var page = doc.GetNumber(KeyStore.Page, -1); - if (page === curPage || page === -1) + if (page === curPage || page === -1) { prev.push(); + } return prev; - }, [] as JSX.Element[]) + }, [] as JSX.Element[]); } @computed @@ -295,8 +298,8 @@ export class CollectionFreeFormView extends CollectionSubView { layoutKey={KeyStore.OverlayLayout} isTopMost={this.props.isTopMost} isSelected={() => false} select={() => { }} />); } - getTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-COLLECTION_BORDER_WIDTH, -COLLECTION_BORDER_WIDTH).translate(-this.centeringShiftX, -this.centeringShiftY).transform(this.getLocalTransform()) - getContainerTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-COLLECTION_BORDER_WIDTH, -COLLECTION_BORDER_WIDTH) + getTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-COLLECTION_BORDER_WIDTH, -COLLECTION_BORDER_WIDTH).translate(-this.centeringShiftX, -this.centeringShiftY).transform(this.getLocalTransform()); + getContainerTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-COLLECTION_BORDER_WIDTH, -COLLECTION_BORDER_WIDTH); getLocalTransform = (): Transform => Transform.Identity().scale(1 / this.scale).translate(this.panX, this.panY); noScaling = () => 1; childViews = () => this.views; diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 704db1d4a..1e6faafb3 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -37,7 +37,7 @@ export class MarqueeView extends React.Component @action cleanupInteractions = (all: boolean = false) => { if (all) { - document.removeEventListener("pointermove", this.onPointerMove, true) + document.removeEventListener("pointermove", this.onPointerMove, true); document.removeEventListener("pointerup", this.onPointerUp, true); } else { this._used = true; @@ -52,7 +52,7 @@ export class MarqueeView extends React.Component this._downX = this._lastX = e.pageX; this._downY = this._lastY = e.pageY; this._used = false; - document.addEventListener("pointermove", this.onPointerMove, true) + document.addEventListener("pointermove", this.onPointerMove, true); document.addEventListener("pointerup", this.onPointerUp, true); document.addEventListener("keydown", this.marqueeCommand, true); } @@ -94,7 +94,7 @@ export class MarqueeView extends React.Component let top = this._downY < this._lastY ? this._downY : this._lastY; let topLeft = this.props.getTransform().transformPoint(left, top); let size = this.props.getTransform().transformDirection(this._lastX - this._downX, this._lastY - this._downY); - return { left: topLeft[0], top: topLeft[1], width: Math.abs(size[0]), height: Math.abs(size[1]) } + return { left: topLeft[0], top: topLeft[1], width: Math.abs(size[0]), height: Math.abs(size[1]) }; } @action @@ -180,9 +180,10 @@ export class MarqueeView extends React.Component var y = doc.GetNumber(KeyStore.Y, 0); var w = doc.GetNumber(KeyStore.Width, 0); var h = doc.GetNumber(KeyStore.Height, 0); - if (this.intersectRect({ left: x, top: y, width: w, height: h }, selRect)) - selection.push(doc) - }) + if (this.intersectRect({ left: x, top: y, width: w, height: h }, selRect)) { + selection.push(doc); + } + }); return selection; } @@ -190,7 +191,7 @@ export class MarqueeView extends React.Component get marqueeDiv() { let p = this.props.getContainerTransform().transformPoint(this._downX < this._lastX ? this._downX : this._lastX, this._downY < this._lastY ? this._downY : this._lastY); let v = this.props.getContainerTransform().transformDirection(this._lastX - this._downX, this._lastY - this._downY); - return
+ return
; } render() { diff --git a/src/client/views/collections/collectionFreeForm/PreviewCursor.tsx b/src/client/views/collections/collectionFreeForm/PreviewCursor.tsx index 599461f85..8eabb020a 100644 --- a/src/client/views/collections/collectionFreeForm/PreviewCursor.tsx +++ b/src/client/views/collections/collectionFreeForm/PreviewCursor.tsx @@ -90,7 +90,7 @@ export class PreviewCursor extends React.Component { {this.props.children}
- ) + ); } } @@ -109,8 +109,9 @@ export class PreviewCursorPrompt extends React.Component { render() { let p = this.props.getPoint(); - if (this.props.getVisible() && this._promptRef.current) + if (this.props.getVisible() && this._promptRef.current) { this._promptRef.current.focus(); + } return
I diff --git a/src/client/views/nodes/Annotation.tsx b/src/client/views/nodes/Annotation.tsx index e4f17940c..3e4ed6bf1 100644 --- a/src/client/views/nodes/Annotation.tsx +++ b/src/client/views/nodes/Annotation.tsx @@ -1,8 +1,8 @@ import "./ImageBox.scss"; -import React = require("react") -import { observer } from "mobx-react" +import React = require("react"); +import { observer } from "mobx-react"; import { observable, action } from 'mobx'; -import 'react-pdf/dist/Page/AnnotationLayer.css' +import 'react-pdf/dist/Page/AnnotationLayer.css'; interface IProps { Span: HTMLSpanElement; @@ -29,13 +29,13 @@ export class Annotation extends React.Component { */ onColorChange = (e: React.PointerEvent) => { if (e.currentTarget.innerHTML === "r") { - this.props.Span.style.backgroundColor = "rgba(255,0,0, 0.3)" + this.props.Span.style.backgroundColor = "rgba(255,0,0, 0.3)"; } else if (e.currentTarget.innerHTML === "b") { - this.props.Span.style.backgroundColor = "rgba(0,255, 255, 0.3)" + this.props.Span.style.backgroundColor = "rgba(0,255, 255, 0.3)"; } else if (e.currentTarget.innerHTML === "y") { - this.props.Span.style.backgroundColor = "rgba(255,255,0, 0.3)" + this.props.Span.style.backgroundColor = "rgba(255,255,0, 0.3)"; } else if (e.currentTarget.innerHTML === "g") { - this.props.Span.style.backgroundColor = "rgba(76, 175, 80, 0.3)" + this.props.Span.style.backgroundColor = "rgba(76, 175, 80, 0.3)"; } } @@ -54,11 +54,11 @@ export class Annotation extends React.Component { this.props.Highlights.splice(index, 1); } } - }) + }); //removing from CurrAnno and Annotation array this.props.Annotations.splice(index, 1); - this.props.CurrAnno.pop() + this.props.CurrAnno.pop(); //removing span from div if (this.props.Span.parentElement) { @@ -70,11 +70,11 @@ export class Annotation extends React.Component { if (item === e) { item.remove(); } - }) + }); e.remove(); } } - }) + }); } diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx index 1bd934c25..1493ff25b 100644 --- a/src/client/views/nodes/AudioBox.tsx +++ b/src/client/views/nodes/AudioBox.tsx @@ -1,18 +1,18 @@ -import React = require("react") +import React = require("react"); import { FieldViewProps, FieldView } from './FieldView'; import { FieldWaiting } from '../../../fields/Field'; -import { observer } from "mobx-react" +import { observer } from "mobx-react"; import { ContextMenu } from "../../views/ContextMenu"; import { observable, action } from 'mobx'; import { KeyStore } from '../../../fields/KeyStore'; import { AudioField } from "../../../fields/AudioField"; -import "./AudioBox.scss" +import "./AudioBox.scss"; import { NumberField } from "../../../fields/NumberField"; @observer export class AudioBox extends React.Component { - public static LayoutString() { return FieldView.LayoutString(AudioBox) } + public static LayoutString() { return FieldView.LayoutString(AudioBox); } constructor(props: FieldViewProps) { super(props); @@ -28,7 +28,7 @@ export class AudioBox extends React.Component { render() { - let field = this.props.Document.Get(this.props.fieldKey) + let field = this.props.Document.Get(this.props.fieldKey); let path = field === FieldWaiting ? "http://techslides.com/demos/samples/sample.mp3" : field instanceof AudioField ? field.Data.href : "http://techslides.com/demos/samples/sample.mp3"; @@ -39,6 +39,6 @@ export class AudioBox extends React.Component { Not supported.
- ) + ); } } \ No newline at end of file diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index dcf82ccd4..77f41105f 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -35,24 +35,24 @@ export class CollectionFreeFormDocumentView extends React.Component this.nativeWidth > 0 ? this.width / this.nativeWidth : 1 + contentScaling = () => this.nativeWidth > 0 ? this.width / this.nativeWidth : 1; getTransform = (): Transform => this.props.ScreenToLocalTransform() @@ -66,7 +66,7 @@ export class CollectionFreeFormDocumentView extends React.Component + />; } panelWidth = () => this.props.Document.GetBoolean(KeyStore.Minimized, false) ? 10 : this.props.PanelWidth(); panelHeight = () => this.props.Document.GetBoolean(KeyStore.Minimized, false) ? 10 : this.props.PanelHeight(); diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index 34cc326aa..5836da396 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -26,7 +26,7 @@ import { FieldViewProps } from "./FieldView"; import { Without } from "../../../Utils"; const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this? -type BindingProps = Without +type BindingProps = Without; export interface JsxBindings { props: BindingProps; [keyName: string]: BindingProps | Field; @@ -92,7 +92,7 @@ export class DocumentContentsView extends React.Component { console.log(test) }} - /> + onError={(test: any) => { console.log(test); }} + />; } } \ No newline at end of file diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index ab9cd2d53..9670ca6b2 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -100,8 +100,9 @@ export class DocumentView extends React.Component { if (e.shiftKey && e.buttons === 2) { if (this.props.isTopMost) { this.startDragging(e.pageX, e.pageY, e.altKey || e.ctrlKey); - } else + } else { CollectionDockingView.Instance.StartOtherDrag([this.props.Document], e); + } e.stopPropagation(); } else { if (this.active && !e.isDefaultPrevented()) { @@ -112,7 +113,7 @@ export class DocumentView extends React.Component { document.addEventListener("pointerup", this.onPointerUp); } } - }; + } private dropDisposer?: DragManager.DragDropDisposer; @@ -179,7 +180,7 @@ export class DocumentView extends React.Component { } e.stopPropagation(); e.preventDefault(); - }; + } onPointerUp = (e: PointerEvent): void => { document.removeEventListener("pointermove", this.onPointerMove); document.removeEventListener("pointerup", this.onPointerUp); @@ -190,22 +191,22 @@ export class DocumentView extends React.Component { ) { SelectionManager.SelectDoc(this, e.ctrlKey); } - }; + } stopPropogation = (e: React.SyntheticEvent) => { e.stopPropagation(); - }; + } deleteClicked = (): void => { if (this.props.removeDocument) { this.props.removeDocument(this.props.Document); } - }; + } fieldsClicked = (e: React.MouseEvent): void => { if (this.props.addDocument) { this.props.addDocument(Documents.KVPDocument(this.props.Document, { width: 300, height: 300 }), false); } - }; + } fullScreenClicked = (e: React.MouseEvent): void => { CollectionDockingView.Instance.OpenFullScreen(this.props.Document); ContextMenu.Instance.clearItems(); @@ -214,7 +215,7 @@ export class DocumentView extends React.Component { event: this.closeFullScreenClicked }); ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15); - }; + } closeFullScreenClicked = (e: React.MouseEvent): void => { CollectionDockingView.Instance.CloseFullScreen(); @@ -224,7 +225,7 @@ export class DocumentView extends React.Component { event: this.fullScreenClicked }); ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15); - }; + } @action public minimize = (): void => { @@ -234,7 +235,7 @@ export class DocumentView extends React.Component { BooleanField ); SelectionManager.DeselectAll(); - }; + } @action drop = (e: Event, de: DragManager.DropEvent) => { @@ -276,7 +277,7 @@ export class DocumentView extends React.Component { ); e.stopPropagation(); } - }; + } onDrop = (e: React.DragEvent) => { if (e.isDefaultPrevented()) { @@ -290,7 +291,7 @@ export class DocumentView extends React.Component { e.stopPropagation(); e.preventDefault(); } - }; + } @action onContextMenu = (e: React.MouseEvent): void => { @@ -352,14 +353,14 @@ export class DocumentView extends React.Component { }); ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15); SelectionManager.SelectDoc(this, e.ctrlKey); - }; + } isMinimized = () => { let field = this.props.Document.GetT(KeyStore.Minimized, BooleanField); if (field && field !== FieldWaiting) { return field.Data; } - }; + } @action expand = () => { @@ -368,13 +369,13 @@ export class DocumentView extends React.Component { false as boolean, BooleanField ); - }; + } - isSelected = () => SelectionManager.IsSelected(this) + isSelected = () => SelectionManager.IsSelected(this); select = (ctrlPressed: boolean) => { SelectionManager.SelectDoc(this, ctrlPressed); - }; + } render() { if (!this.props.Document) { diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index d9422ae9b..07c5b332c 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -1,4 +1,4 @@ -import React = require("react") +import React = require("react"); import { observer } from "mobx-react"; import { computed } from "mobx"; import { Field, FieldWaiting, FieldValue } from "../../../fields/Field"; @@ -7,7 +7,7 @@ import { TextField } from "../../../fields/TextField"; import { NumberField } from "../../../fields/NumberField"; import { RichTextField } from "../../../fields/RichTextField"; import { ImageField } from "../../../fields/ImageField"; -import { VideoField } from "../../../fields/VideoField" +import { VideoField } from "../../../fields/VideoField"; import { Key } from "../../../fields/Key"; import { FormattedTextBox } from "./FormattedTextBox"; import { ImageBox } from "./ImageBox"; @@ -57,22 +57,22 @@ export class FieldView extends React.Component { render() { const field = this.field; if (!field) { - return

{''}

+ return

{''}

; } if (field instanceof TextField) { - return

{field.Data}

+ return

{field.Data}

; } else if (field instanceof RichTextField) { - return + return ; } else if (field instanceof ImageField) { - return + return ; } else if (field instanceof VideoField) { - return + return ; } else if (field instanceof AudioField) { - return + return ; } else if (field instanceof Document) { return ( @@ -92,25 +92,26 @@ export class FieldView extends React.Component { ContainingCollectionView={undefined} parentActive={this.props.active} onActiveChanged={this.props.onActiveChanged} /> - ) + ); } else if (field instanceof ListField) { return (
{(field as ListField).Data.map(f => f instanceof Document ? f.Title : f.GetValue().toString()).join(", ")} -
) +
); } // bcz: this belongs here, but it doesn't render well so taking it out for now // else if (field instanceof HtmlField) { // return // } else if (field instanceof NumberField) { - return

{field.Data}

+ return

{field.Data}

; } else if (field !== FieldWaiting) { - return

{JSON.stringify(field.GetValue())}

+ return

{JSON.stringify(field.GetValue())}

; } - else - return

{"Waiting for server..."}

+ else { + return

{"Waiting for server..."}

; + } } } \ No newline at end of file diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 7a94be12b..beca6cdc6 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -61,7 +61,7 @@ export class FormattedTextBox extends React.Component { ); // doc.SetData(fieldKey, JSON.stringify(state.toJSON()), RichTextField); } - }; + } get FieldDoc() { return this.props.fieldKey === KeyStore.Archives ? Main.Instance._textDoc! : this.props.Document; } get FieldKey() { return this.props.fieldKey === KeyStore.Archives ? KeyStore.Data : this.props.fieldKey; } @@ -81,12 +81,13 @@ export class FormattedTextBox extends React.Component { if (this.props.fieldKey === KeyStore.Archives) { this._inputReactionDisposer = reaction(() => Main.Instance._textDoc && Main.Instance._textDoc.Id, () => { - if (this._editorView) - this._editorView!.destroy(); + if (this._editorView) { + this._editorView.destroy(); + } this.setupEditor(config); } - ) + ); } this._reactionDisposer = reaction( @@ -153,7 +154,7 @@ export class FormattedTextBox extends React.Component { if (e.buttons === 1 && this.props.isSelected() && !e.altKey) { e.stopPropagation(); } - }; + } onPointerUp = (e: React.PointerEvent): void => { if (e.buttons === 1 && this.props.isSelected() && !e.altKey) { e.stopPropagation(); @@ -162,7 +163,7 @@ export class FormattedTextBox extends React.Component { e.preventDefault(); Main.Instance.SetTextDoc(this.props.Document, this._ref.current!); } - }; + } onFocused = (e: React.FocusEvent): void => { if (this.props.fieldKey !== KeyStore.Archives) { @@ -191,11 +192,11 @@ export class FormattedTextBox extends React.Component { // ] // }) // e.stopPropagation() - }; + } onPointerWheel = (e: React.WheelEvent): void => { e.stopPropagation(); - }; + } tooltipMenuPlugin() { return new Plugin({ diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index c5f29f7b0..6b0a3a799 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -9,13 +9,13 @@ import { KeyStore } from '../../../fields/KeyStore'; import { ContextMenu } from "../../views/ContextMenu"; import { FieldView, FieldViewProps } from './FieldView'; import "./ImageBox.scss"; -import React = require("react") +import React = require("react"); import { Utils } from '../../../Utils'; @observer export class ImageBox extends React.Component { - public static LayoutString() { return FieldView.LayoutString(ImageBox) } + public static LayoutString() { return FieldView.LayoutString(ImageBox); } private _ref: React.RefObject; private _imgRef: React.RefObject; private _downX: number = 0; @@ -39,7 +39,7 @@ export class ImageBox extends React.Component { onLoad = (target: any) => { var h = this._imgRef.current!.naturalHeight; var w = this._imgRef.current!.naturalWidth; - this.props.Document.SetNumber(KeyStore.NativeHeight, this.props.Document.GetNumber(KeyStore.NativeWidth, 0) * h / w) + this.props.Document.SetNumber(KeyStore.NativeHeight, this.props.Document.GetNumber(KeyStore.NativeWidth, 0) * h / w); } componentDidMount() { @@ -86,7 +86,7 @@ export class ImageBox extends React.Component { onMoveNextRequest={action(() => this._photoIndex = (this._photoIndex + 1) % images.length )} - />) + />); } } @@ -96,7 +96,7 @@ export class ImageBox extends React.Component { let url = field.Data.href; ContextMenu.Instance.addItem({ description: "Copy path", event: () => { - Utils.CopyText(url) + Utils.CopyText(url); } }); } @@ -111,6 +111,6 @@ export class ImageBox extends React.Component {
Image not found {this.lightbox(path)} -
) +
); } } \ No newline at end of file diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx index 8a7f32e6d..bcac113f0 100644 --- a/src/client/views/nodes/KeyValueBox.tsx +++ b/src/client/views/nodes/KeyValueBox.tsx @@ -7,7 +7,7 @@ import { KeyStore } from '../../../fields/KeyStore'; import { FieldView, FieldViewProps } from './FieldView'; import "./KeyValueBox.scss"; import { KeyValuePair } from "./KeyValuePair"; -import React = require("react") +import React = require("react"); import { CompileScript, ToField } from "../../util/Scripting"; import { Key } from '../../../fields/Key'; import { observable, action } from "mobx"; @@ -15,7 +15,7 @@ import { observable, action } from "mobx"; @observer export class KeyValueBox extends React.Component { - public static LayoutString(fieldStr: string = "DataKey") { return FieldView.LayoutString(KeyValueBox, fieldStr) } + public static LayoutString(fieldStr: string = "DataKey") { return FieldView.LayoutString(KeyValueBox, fieldStr); } @observable private _keyInput: string = ""; @observable private _valueInput: string = ""; @@ -36,7 +36,7 @@ export class KeyValueBox extends React.Component { if (this._keyInput && this._valueInput) { let doc = this.props.Document.GetT(KeyStore.Data, Document); if (!doc || doc === FieldWaiting) { - return + return; } let realDoc = doc; @@ -55,8 +55,8 @@ export class KeyValueBox extends React.Component { realDoc.Set(new Key(this._keyInput), dataField); } } - this._keyInput = "" - this._valueInput = "" + this._keyInput = ""; + this._valueInput = ""; } } } @@ -73,7 +73,7 @@ export class KeyValueBox extends React.Component { createTable = () => { let doc = this.props.Document.GetT(KeyStore.Data, Document); if (!doc || doc === FieldWaiting) { - return Loading... + return Loading...; } let realDoc = doc; @@ -84,13 +84,13 @@ export class KeyValueBox extends React.Component { if (!(key in ids)) { ids[key] = key; } - }) + }); } let rows: JSX.Element[] = []; let i = 0; for (let key in ids) { - rows.push() + rows.push(); } return rows; } @@ -125,6 +125,6 @@ export class KeyValueBox extends React.Component { {this.newKeyValue()} -
) +
); } } \ No newline at end of file diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx index c6a0a7296..a1050dc6e 100644 --- a/src/client/views/nodes/KeyValuePair.tsx +++ b/src/client/views/nodes/KeyValuePair.tsx @@ -1,14 +1,14 @@ import 'react-image-lightbox/style.css'; // This only needs to be imported once in your app import "./KeyValueBox.scss"; import "./KeyValuePair.scss"; -import React = require("react") +import React = require("react"); import { FieldViewProps, FieldView } from './FieldView'; import { Opt, Field } from '../../../fields/Field'; -import { observer } from "mobx-react" +import { observer } from "mobx-react"; import { observable, action } from 'mobx'; import { Document } from '../../../fields/Document'; import { Key } from '../../../fields/Key'; -import { Server } from "../../Server" +import { Server } from "../../Server"; import { EditableView } from "../EditableView"; import { CompileScript, ToField } from "../../util/Scripting"; import { Transform } from '../../util/Transform'; @@ -25,7 +25,7 @@ export interface KeyValuePairProps { export class KeyValuePair extends React.Component { @observable - private key: Opt + private key: Opt; constructor(props: KeyValuePairProps) { super(props); @@ -41,7 +41,7 @@ export class KeyValuePair extends React.Component { render() { if (!this.key) { - return error + return error; } let props: FieldViewProps = { @@ -55,7 +55,7 @@ export class KeyValuePair extends React.Component { onActiveChanged: emptyFunction, ScreenToLocalTransform: Transform.Identity, focus: emptyFunction, - } + }; let contents = ( ); @@ -101,6 +101,6 @@ export class KeyValuePair extends React.Component { return false; }}> - ) + ); } } \ No newline at end of file diff --git a/src/client/views/nodes/LinkBox.tsx b/src/client/views/nodes/LinkBox.tsx index 4791d6029..b016a3d48 100644 --- a/src/client/views/nodes/LinkBox.tsx +++ b/src/client/views/nodes/LinkBox.tsx @@ -2,8 +2,8 @@ import { observable, computed, action } from "mobx"; import React = require("react"); import { SelectionManager } from "../../util/SelectionManager"; import { observer } from "mobx-react"; -import './LinkBox.scss' -import { KeyStore } from '../../../fields/KeyStore' +import './LinkBox.scss'; +import { KeyStore } from '../../../fields/KeyStore'; import { props } from "bluebird"; import { DocumentView } from "./DocumentView"; import { Document } from "../../../fields/Document"; @@ -30,7 +30,7 @@ interface Props { linkName: String; pairedDoc: Document; type: String; - showEditor: () => void + showEditor: () => void; } @observer @@ -49,15 +49,16 @@ export class LinkBox extends React.Component { } else if (contextDoc instanceof Document) { this.props.pairedDoc.GetTAsync(KeyStore.Page, NumberField).then((pfield: any) => { contextDoc.GetTAsync(KeyStore.CurPage, NumberField).then((cfield: any) => { - if (pfield !== cfield) + if (pfield !== cfield) { contextDoc.SetNumber(KeyStore.CurPage, pfield.Data); + } let contextView = DocumentManager.Instance.getDocumentView(contextDoc); if (contextView) { contextView.props.focus(contextDoc); } else { CollectionDockingView.Instance.AddRightSplit(contextDoc); } - }) + }); }); } }); @@ -80,7 +81,7 @@ export class LinkBox extends React.Component { if (field) { field.Data.splice(field.Data.indexOf(this.props.linkDoc)); } - }) + }); } }); this.props.linkDoc.GetTAsync(KeyStore.LinkedToDocs, Document, field => { @@ -89,7 +90,7 @@ export class LinkBox extends React.Component { if (field) { field.Data.splice(field.Data.indexOf(this.props.linkDoc)); } - }) + }); } }); } @@ -117,6 +118,6 @@ export class LinkBox extends React.Component {
- ) + ); } } \ No newline at end of file diff --git a/src/client/views/nodes/LinkEditor.tsx b/src/client/views/nodes/LinkEditor.tsx index 3f7b4bf2d..bde50fed8 100644 --- a/src/client/views/nodes/LinkEditor.tsx +++ b/src/client/views/nodes/LinkEditor.tsx @@ -2,8 +2,8 @@ import { observable, computed, action } from "mobx"; import React = require("react"); import { SelectionManager } from "../../util/SelectionManager"; import { observer } from "mobx-react"; -import './LinkEditor.scss' -import { KeyStore } from '../../../fields/KeyStore' +import './LinkEditor.scss'; +import { KeyStore } from '../../../fields/KeyStore'; import { props } from "bluebird"; import { DocumentView } from "./DocumentView"; import { Document } from "../../../fields/Document"; @@ -43,7 +43,7 @@ export class LinkEditor extends React.Component {
SAVE
- ) + ); } @action diff --git a/src/client/views/nodes/LinkMenu.tsx b/src/client/views/nodes/LinkMenu.tsx index 6c2d24630..ac09da305 100644 --- a/src/client/views/nodes/LinkMenu.tsx +++ b/src/client/views/nodes/LinkMenu.tsx @@ -13,7 +13,7 @@ import React = require("react"); interface Props { docView: DocumentView; - changeFlyout: () => void + changeFlyout: () => void; } @observer @@ -25,9 +25,9 @@ export class LinkMenu extends React.Component { return links.map(link => { let doc = link.GetT(key, Document); if (doc && doc !== FieldWaiting) { - return this._editingLink = link)} type={type} /> + return this._editingLink = link)} type={type} />; } - }) + }); } render() { @@ -43,11 +43,11 @@ export class LinkMenu extends React.Component { {this.renderLinkItems(linkFrom, KeyStore.LinkedFromDocs, "Source: ")}
- ) + ); } else { return ( this._editingLink = undefined)}> - ) + ); } } diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 774d9be3e..81ceb37f6 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -17,7 +17,7 @@ import { FieldView, FieldViewProps } from './FieldView'; import "./ImageBox.scss"; import "./PDFBox.scss"; import { Sticky } from './Sticky'; //you should look at sticky and annotation, because they are used here -import React = require("react") +import React = require("react"); import { SelectionManager } from "../../util/SelectionManager"; /** ALSO LOOK AT: Annotation.tsx, Sticky.tsx @@ -55,7 +55,7 @@ import { SelectionManager } from "../../util/SelectionManager"; export class PDFBox extends React.Component { public static LayoutString() { return FieldView.LayoutString(PDFBox); } - private _mainDiv = React.createRef() + private _mainDiv = React.createRef(); private _pdf = React.createRef(); @observable private _renderAsSvg = true; @@ -72,7 +72,7 @@ export class PDFBox extends React.Component { private _currTool: any; //keeps track of current tool button reference private _drawToolOn: boolean = false; //boolean that keeps track of the drawing tool - private _drawTool = React.createRef()//drawing tool button reference + private _drawTool = React.createRef();//drawing tool button reference private _colorTool = React.createRef(); //color button reference private _currColor: string = "black"; //current color that user selected (for ink/pen) @@ -85,7 +85,7 @@ export class PDFBox extends React.Component { @observable private _perPageInfo: Object[] = []; //stores pageInfo @observable private _pageInfo: any = { area: [], divs: [], anno: [] }; //divs is array of objects linked to anno - @observable private _currAnno: any = [] + @observable private _currAnno: any = []; @observable private _interactive: boolean = false; @observable private _loaded: boolean = false; @@ -168,24 +168,24 @@ export class PDFBox extends React.Component { let obj: Object = { parentDivs: [], spans: [] }; //@ts-ignore if (range.commonAncestorContainer.className === 'react-pdf__Page__textContent') { //multiline highlighting case - obj = this.highlightNodes(range.commonAncestorContainer.childNodes) + obj = this.highlightNodes(range.commonAncestorContainer.childNodes); } else { //single line highlighting case - let parentDiv = range.commonAncestorContainer.parentElement + let parentDiv = range.commonAncestorContainer.parentElement; if (parentDiv) { if (parentDiv.className === 'react-pdf__Page__textContent') { //when highlight is overwritten - obj = this.highlightNodes(parentDiv.childNodes) + obj = this.highlightNodes(parentDiv.childNodes); } else { parentDiv.childNodes.forEach((child) => { if (child.nodeName === 'SPAN') { //@ts-ignore - obj.parentDivs.push(parentDiv) + obj.parentDivs.push(parentDiv); //@ts-ignore - child.id = "highlighted" + child.id = "highlighted"; //@ts-ignore - obj.spans.push(child) + obj.spans.push(child); child.addEventListener("mouseover", this.onEnter); //adds mouseover annotation handler } - }) + }); } } } @@ -196,21 +196,21 @@ export class PDFBox extends React.Component { } highlightNodes = (nodes: NodeListOf) => { - let temp = { parentDivs: [], spans: [] } + let temp = { parentDivs: [], spans: [] }; nodes.forEach((div) => { div.childNodes.forEach((child) => { if (child.nodeName === 'SPAN') { //@ts-ignore - temp.parentDivs.push(div) + temp.parentDivs.push(div); //@ts-ignore - child.id = "highlighted" + child.id = "highlighted"; //@ts-ignore - temp.spans.push(child) + temp.spans.push(child); child.addEventListener("mouseover", this.onEnter); //adds mouseover annotation handler } - }) + }); - }) + }); return temp; } @@ -228,8 +228,8 @@ export class PDFBox extends React.Component { index = this._pageInfo.divs.indexOf(obj); } } - }) - }) + }); + }); if (this._pageInfo.anno.length >= index + 1) { if (this._currAnno.length === 0) { @@ -239,13 +239,13 @@ export class PDFBox extends React.Component { if (this._currAnno.length === 0) { //if there are no current annotation let div = span.offsetParent; //@ts-ignore - let divX = div.style.left + let divX = div.style.left; //@ts-ignore - let divY = div.style.top + let divY = div.style.top; //slicing "px" from the end divX = divX.slice(0, divX.length - 2); //gets X of the DIV element (parent of Span) divY = divY.slice(0, divY.length - 2); //gets Y of the DIV element (parent of Span) - let annotation = + let annotation = ; this._pageInfo.anno.push(annotation); this._currAnno.push(annotation); } @@ -263,7 +263,7 @@ export class PDFBox extends React.Component { this.makeEditableAndHighlight(color); } } catch (ex) { - this.makeEditableAndHighlight(color) + this.makeEditableAndHighlight(color); } } } @@ -305,7 +305,7 @@ export class PDFBox extends React.Component { } if (this._mainDiv.current) { - let sticky = + let sticky = ; this._pageInfo.area.push(sticky); } this._toolOn = false; @@ -404,19 +404,19 @@ export class PDFBox extends React.Component { if (e instanceof HTMLCanvasElement) { this._pdfCanvas = e; - this._pdfContext = e.getContext("2d") + this._pdfContext = e.getContext("2d"); } - }) + }); } - }) + }); } // bcz: the number of pages should really be set when the document is imported. this.props.Document.SetNumber(KeyStore.NumPages, page._transport.numPages); if (this._perPageInfo.length === 0) { //Makes sure it only runs once - this._perPageInfo = [...Array(page._transport.numPages)] + this._perPageInfo = [...Array(page._transport.numPages)]; } this._loaded = true; } diff --git a/src/client/views/nodes/Sticky.tsx b/src/client/views/nodes/Sticky.tsx index 4a4d69e90..11719831b 100644 --- a/src/client/views/nodes/Sticky.tsx +++ b/src/client/views/nodes/Sticky.tsx @@ -39,7 +39,7 @@ export class Sticky extends React.Component { document.addEventListener("pointermove", this.drawMove); document.addEventListener("pointerup", this.drawUp); } - }; + } //when user drags drawMove = (e: PointerEvent): void => { @@ -49,7 +49,7 @@ export class Sticky extends React.Component { //connects the point this.ctx.lineTo(x, y); this.ctx.stroke(); - }; + } /** * when user lifts the mouse, the drawing ends @@ -58,7 +58,7 @@ export class Sticky extends React.Component { this.ctx.closePath(); console.log(this.ctx); document.removeEventListener("pointermove", this.drawMove); - }; + } render() { return ( diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index a08b320e8..314af64c9 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -1,4 +1,4 @@ -import React = require("react") +import React = require("react"); import { observer } from "mobx-react"; import { FieldWaiting, Opt } from '../../../fields/Field'; import { VideoField } from '../../../fields/VideoField'; @@ -13,8 +13,8 @@ import { number } from "prop-types"; export class VideoBox extends React.Component { private _reactionDisposer: Opt; - private _videoRef = React.createRef() - public static LayoutString() { return FieldView.LayoutString(VideoBox) } + private _videoRef = React.createRef(); + public static LayoutString() { return FieldView.LayoutString(VideoBox); } constructor(props: FieldViewProps) { super(props); @@ -58,7 +58,7 @@ export class VideoBox extends React.Component { render() { let field = this.props.Document.GetT(this.props.fieldKey, VideoField); if (!field || field === FieldWaiting) { - return
Loading
+ return
Loading
; } let path = field.Data.href; trace(); @@ -73,6 +73,6 @@ export class VideoBox extends React.Component { } - ) + ); } } \ No newline at end of file diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index c1d389001..90ce72c41 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -1,9 +1,9 @@ import "./WebBox.scss"; -import React = require("react") +import React = require("react"); import { WebField } from '../../../fields/WebField'; import { FieldViewProps, FieldView } from './FieldView'; import { FieldWaiting } from '../../../fields/Field'; -import { observer } from "mobx-react" +import { observer } from "mobx-react"; import { computed } from 'mobx'; import { KeyStore } from '../../../fields/KeyStore'; @@ -33,6 +33,6 @@ export class WebBox extends React.Component { return (
{content} -
) + ); } } \ No newline at end of file diff --git a/src/debug/Test.tsx b/src/debug/Test.tsx index c8de33f41..11f2b0c4e 100644 --- a/src/debug/Test.tsx +++ b/src/debug/Test.tsx @@ -1,10 +1,10 @@ import * as React from 'react'; import * as ReactDOM from 'react-dom'; -import JsxParser from 'react-jsx-parser' +import JsxParser from 'react-jsx-parser'; class Hello extends React.Component<{ firstName: string, lastName: string }> { render() { - return
Hello {this.props.firstName} {this.props.lastName}
+ return
Hello {this.props.firstName} {this.props.lastName}
; } } @@ -16,8 +16,8 @@ class Test extends React.Component { firstName: "First", lastName: "Last" } - } - return + }; + return ; } } diff --git a/src/debug/Viewer.tsx b/src/debug/Viewer.tsx index f13cccd24..857da1ebb 100644 --- a/src/debug/Viewer.tsx +++ b/src/debug/Viewer.tsx @@ -40,22 +40,22 @@ class ListViewer extends React.Component<{ field: ListField }>{
{this.props.field.Data.map(field => )}
- ) + ); } else { - content = <>[...] ({this.props.field.Id}) + content = <>[...] ({this.props.field.Id}); } return (
{content}
- ) + ); } } @observer class DocumentViewer extends React.Component<{ field: Document }> { - private keyMap: ObservableMap = new ObservableMap + private keyMap: ObservableMap = new ObservableMap; private disposer?: Lambda; @@ -67,12 +67,12 @@ class DocumentViewer extends React.Component<{ field: Document }> { if (field && field instanceof Key) { this.keyMap.set(id, field); } - }) + }); } }); - } - this.disposer = this.props.field._proxies.observe(f) - f() + }; + this.disposer = this.props.field._proxies.observe(f); + f(); } componentWillUnmount() { @@ -89,8 +89,8 @@ class DocumentViewer extends React.Component<{ field: Document }> { ({key ? key.Name : kv[0]}): - ) - }) + ); + }); return (
Document ({this.props.field.Id}) @@ -98,7 +98,7 @@ class DocumentViewer extends React.Component<{ field: Document }> { {fields}
- ) + ); } } @@ -111,15 +111,15 @@ class DebugViewer extends React.Component<{ fieldId: string }> { private error?: string; constructor(props: { fieldId: string }) { - super(props) - this.update() + super(props); + this.update(); } update() { Server.GetField(this.props.fieldId, action((field: Opt) => { this.field = field; if (!field) { - this.error = `Field with id ${this.props.fieldId} not found` + this.error = `Field with id ${this.props.fieldId} not found`; } })); @@ -130,20 +130,20 @@ class DebugViewer extends React.Component<{ fieldId: string }> { if (this.field) { // content = this.field.ToJson(); if (this.field instanceof ListField) { - content = () + content = (); } else if (this.field instanceof Document) { - content = () + content = (); } else if (this.field instanceof BasicField) { - content = () + content = (); } else if (this.field instanceof Key) { - content = () + content = (); } else { - content = (Unrecognized field type) + content = (Unrecognized field type); } } else if (this.error) { - content = Field {this.props.fieldId} not found + content = Field {this.props.fieldId} not found ; } else { - content = Field loading: {this.props.fieldId} + content = Field loading: {this.props.fieldId}; } return content; } @@ -165,8 +165,8 @@ class Viewer extends React.Component { @action onKeyPress = (e: React.KeyboardEvent) => { if (e.key === "Enter") { - this.ids.push(this.idToAdd) - this.idToAdd = "" + this.ids.push(this.idToAdd); + this.idToAdd = ""; } } @@ -180,7 +180,7 @@ class Viewer extends React.Component { {this.ids.map(id => )} - ) + ); } } diff --git a/src/fields/AudioField.ts b/src/fields/AudioField.ts index 252a5b74e..996d2556d 100644 --- a/src/fields/AudioField.ts +++ b/src/fields/AudioField.ts @@ -25,7 +25,7 @@ export class AudioField extends BasicField { type: Types.Audio, data: this.Data.href, _id: this.Id - } + }; } } \ No newline at end of file diff --git a/src/fields/BasicField.ts b/src/fields/BasicField.ts index 3083a1937..17b1fc4e8 100644 --- a/src/fields/BasicField.ts +++ b/src/fields/BasicField.ts @@ -1,4 +1,4 @@ -import { Field, FieldId } from "./Field" +import { Field, FieldId } from "./Field"; import { observable, computed, action } from "mobx"; import { Server } from "../client/Server"; import { UndoManager } from "../client/util/UndoManager"; @@ -9,7 +9,7 @@ export abstract class BasicField extends Field { this.data = data; if (save) { - Server.UpdateField(this) + Server.UpdateField(this); } } @@ -36,7 +36,7 @@ export abstract class BasicField extends Field { UndoManager.AddEvent({ undo: () => this.Data = oldValue, redo: () => this.Data = value - }) + }); Server.UpdateField(this); } diff --git a/src/fields/Document.ts b/src/fields/Document.ts index 4fa478f32..4584660fb 100644 --- a/src/fields/Document.ts +++ b/src/fields/Document.ts @@ -37,21 +37,24 @@ export class Document extends Field { } } - public Width = () => this.GetNumber(KeyStore.Width, 0) + public Width = () => this.GetNumber(KeyStore.Width, 0); public Height = () => this.GetNumber(KeyStore.Height, this.GetNumber(KeyStore.NativeWidth, 0) ? (this.GetNumber(KeyStore.NativeHeight, 0) / this.GetNumber(KeyStore.NativeWidth, 0)) * this.GetNumber(KeyStore.Width, 0) : 0); - public Scale = () => this.GetNumber(KeyStore.Scale, 1) + public Scale = () => this.GetNumber(KeyStore.Scale, 1); @computed public get Title(): string { let title = this.Get(KeyStore.Title, true); - if (title) - if (title !== FieldWaiting && title instanceof TextField) + if (title) { + if (title !== FieldWaiting && title instanceof TextField) { return title.Data; + } else return "-waiting-"; + } let parTitle = this.GetT(KeyStore.Title, TextField); - if (parTitle) + if (parTitle) { if (parTitle !== FieldWaiting) return parTitle.Data + ".alias"; else return "-waiting-.alias"; + } return "-untitled-"; } @@ -398,11 +401,13 @@ export class Document extends Field { } } else - if (field instanceof Document) // ... TODO bcz: should we copy documents or reference them - copy.Set(key!, field) - else if (field) - copy.Set(key!, field.Copy()) - }) + if (field instanceof Document) { // ... TODO bcz: should we copy documents or reference them + copy.Set(key!, field); + } + else if (field) { + copy.Set(key!, field.Copy()); + } + }); } }); return copy; diff --git a/src/fields/DocumentReference.ts b/src/fields/DocumentReference.ts index 9d3c209b4..6c0c1ef82 100644 --- a/src/fields/DocumentReference.ts +++ b/src/fields/DocumentReference.ts @@ -52,6 +52,6 @@ export class DocumentReference extends Field { type: Types.DocumentReference, data: this.document.Id, _id: this.Id - } + }; } } \ No newline at end of file diff --git a/src/fields/Field.ts b/src/fields/Field.ts index 0d0e56f77..d9db23b9e 100644 --- a/src/fields/Field.ts +++ b/src/fields/Field.ts @@ -65,5 +65,5 @@ export abstract class Field { abstract Copy(): Field; - abstract ToJson(): { _id: string, type: Types, data: any } + abstract ToJson(): { _id: string, type: Types, data: any }; } \ No newline at end of file diff --git a/src/fields/HtmlField.ts b/src/fields/HtmlField.ts index 7cbdf7e58..65665cf7a 100644 --- a/src/fields/HtmlField.ts +++ b/src/fields/HtmlField.ts @@ -20,6 +20,6 @@ export class HtmlField extends BasicField { type: Types.Html, data: this.Data, _id: this.Id, - } + }; } } \ No newline at end of file diff --git a/src/fields/ImageField.ts b/src/fields/ImageField.ts index ef616b2ad..dd843026f 100644 --- a/src/fields/ImageField.ts +++ b/src/fields/ImageField.ts @@ -24,6 +24,6 @@ export class ImageField extends BasicField { type: Types.Image, data: this.Data.href, _id: this.Id - } + }; } } \ No newline at end of file diff --git a/src/fields/InkField.ts b/src/fields/InkField.ts index 2a4ed18e7..ab706ee30 100644 --- a/src/fields/InkField.ts +++ b/src/fields/InkField.ts @@ -36,7 +36,7 @@ export class InkField extends BasicField { type: Types.Ink, data: this.Data, _id: this.Id, - } + }; } UpdateFromServer(data: any) { diff --git a/src/fields/Key.ts b/src/fields/Key.ts index 00d78d516..c7f806b88 100644 --- a/src/fields/Key.ts +++ b/src/fields/Key.ts @@ -1,4 +1,4 @@ -import { Field, FieldId } from "./Field" +import { Field, FieldId } from "./Field"; import { Utils } from "../Utils"; import { observable } from "mobx"; import { Types } from "../server/Message"; @@ -16,7 +16,7 @@ export class Key extends Field { this.name = name; if (save) { - Server.UpdateField(this) + Server.UpdateField(this); } } @@ -45,6 +45,6 @@ export class Key extends Field { type: Types.Key, data: this.name, _id: this.Id - } + }; } } \ No newline at end of file diff --git a/src/fields/KeyStore.ts b/src/fields/KeyStore.ts index e24e9c8ec..425408273 100644 --- a/src/fields/KeyStore.ts +++ b/src/fields/KeyStore.ts @@ -56,8 +56,9 @@ export namespace KeyStore { ]; export function KeyLookup(keyid: string) { for (const key of KeyList) { - if (key.Id === keyid) + if (key.Id === keyid) { return key; + } } return undefined; } diff --git a/src/fields/ListField.ts b/src/fields/ListField.ts index 815a3df73..b6eab5f86 100644 --- a/src/fields/ListField.ts +++ b/src/fields/ListField.ts @@ -7,7 +7,7 @@ import { Field, FieldId } from "./Field"; import { FieldMap } from "../client/SocketStub"; export class ListField extends BasicField { - private _proxies: string[] = [] + private _proxies: string[] = []; constructor(data: T[] = [], id?: FieldId, save: boolean = true) { super(data, save, id); this.updateProxies(); @@ -22,23 +22,24 @@ export class ListField extends BasicField { private observeDisposer: Lambda | undefined; private observeList(): void { if (this.observeDisposer) { - this.observeDisposer() + this.observeDisposer(); } this.observeDisposer = observe(this.Data as IObservableArray, (change: IArrayChange | IArraySplice) => { - this.updateProxies() + this.updateProxies(); if (change.type === "splice") { UndoManager.AddEvent({ undo: () => this.Data.splice(change.index, change.addedCount, ...change.removed), redo: () => this.Data.splice(change.index, change.removedCount, ...change.added) - }) + }); } else { UndoManager.AddEvent({ undo: () => this.Data[change.index] = change.oldValue, redo: () => this.Data[change.index] = change.newValue - }) + }); } - if (!this._processingServerUpdate) + if (!this._processingServerUpdate) { Server.UpdateField(this); + } }); } @@ -78,19 +79,23 @@ export class ListField extends BasicField { var proxies = this._proxies.map(p => p); var added = this.data.length < this._proxies.length; var deleted = this.data.length > this._proxies.length; - for (let i = 0; i < dataids.length && added; i++) + for (let i = 0; i < dataids.length && added; i++) { added = proxies.indexOf(dataids[i]) !== -1; - for (let i = 0; i < this._proxies.length && deleted; i++) + } + for (let i = 0; i < this._proxies.length && deleted; i++) { deleted = dataids.indexOf(proxies[i]) !== -1; + } this._processingServerUpdate = true; for (let i = 0; i < proxies.length && added; i++) { - if (dataids.indexOf(proxies[i]) === -1) + if (dataids.indexOf(proxies[i]) === -1) { this.Data.splice(i, 0, fields[proxies[i]] as T); + } } for (let i = dataids.length - 1; i >= 0 && deleted; i--) { - if (proxies.indexOf(dataids[i]) === -1) + if (proxies.indexOf(dataids[i]) === -1) { this.Data.splice(i, 1); + } } if (!added && !deleted) {// otherwise, just rebuild the whole list this.setData(proxies.map(id => fields[id] as T)); @@ -98,7 +103,7 @@ export class ListField extends BasicField { this._processingServerUpdate = false; } callback(this); - })) + })); } ToScriptString(): string { @@ -114,12 +119,12 @@ export class ListField extends BasicField { type: Types.List, data: this._proxies || [], _id: this.Id - } + }; } static FromJson(id: string, ids: string[]): ListField { let list = new ListField([], id, false); list._proxies = ids; - return list + return list; } } \ No newline at end of file diff --git a/src/fields/NumberField.ts b/src/fields/NumberField.ts index e0c8648de..45b920e31 100644 --- a/src/fields/NumberField.ts +++ b/src/fields/NumberField.ts @@ -1,4 +1,4 @@ -import { BasicField } from "./BasicField" +import { BasicField } from "./BasicField"; import { Types } from "../server/Message"; import { FieldId } from "./Field"; @@ -20,6 +20,6 @@ export class NumberField extends BasicField { _id: this.Id, type: Types.Number, data: this.Data - } + }; } } \ No newline at end of file diff --git a/src/fields/PDFField.ts b/src/fields/PDFField.ts index 436c1cf2b..65e179894 100644 --- a/src/fields/PDFField.ts +++ b/src/fields/PDFField.ts @@ -1,6 +1,6 @@ import { BasicField } from "./BasicField"; import { Field, FieldId } from "./Field"; -import { observable } from "mobx" +import { observable } from "mobx"; import { Types } from "../server/Message"; @@ -27,7 +27,7 @@ export class PDFField extends BasicField { type: Types.PDF, data: this.Data.href, _id: this.Id - } + }; } @observable diff --git a/src/fields/RichTextField.ts b/src/fields/RichTextField.ts index 5efb43314..6f7b3074a 100644 --- a/src/fields/RichTextField.ts +++ b/src/fields/RichTextField.ts @@ -20,7 +20,7 @@ export class RichTextField extends BasicField { type: Types.RichText, data: this.Data, _id: this.Id - } + }; } } \ No newline at end of file diff --git a/src/fields/TextField.ts b/src/fields/TextField.ts index 71d8ea310..69d26f42f 100644 --- a/src/fields/TextField.ts +++ b/src/fields/TextField.ts @@ -1,4 +1,4 @@ -import { BasicField } from "./BasicField" +import { BasicField } from "./BasicField"; import { FieldId } from "./Field"; import { Types } from "../server/Message"; @@ -20,6 +20,6 @@ export class TextField extends BasicField { type: Types.Text, data: this.Data, _id: this.Id - } + }; } } \ No newline at end of file diff --git a/src/fields/TupleField.ts b/src/fields/TupleField.ts index e2162c751..ad0f6f350 100644 --- a/src/fields/TupleField.ts +++ b/src/fields/TupleField.ts @@ -21,7 +21,7 @@ export class TupleField extends BasicField<[T, U]> { UndoManager.AddEvent({ undo: () => this.Data[change.index] = change.oldValue, redo: () => this.Data[change.index] = change.newValue - }) + }); Server.UpdateField(this); } else { throw new Error("Why are you messing with the length of a tuple, huh?"); @@ -31,7 +31,7 @@ export class TupleField extends BasicField<[T, U]> { protected setData(value: [T, U]) { if (this.observeDisposer) { - this.observeDisposer() + this.observeDisposer(); } this.data = observable(value) as (T | U)[] as [T, U]; this.observeTuple(); @@ -54,6 +54,6 @@ export class TupleField extends BasicField<[T, U]> { type: Types.Tuple, data: this.Data, _id: this.Id - } + }; } } \ No newline at end of file diff --git a/src/fields/VideoField.ts b/src/fields/VideoField.ts index 992cc1641..d7cd7e968 100644 --- a/src/fields/VideoField.ts +++ b/src/fields/VideoField.ts @@ -24,7 +24,7 @@ export class VideoField extends BasicField { type: Types.Video, data: this.Data.href, _id: this.Id - } + }; } } \ No newline at end of file diff --git a/src/fields/WebField.ts b/src/fields/WebField.ts index 0cbcc6d33..6023e9e6b 100644 --- a/src/fields/WebField.ts +++ b/src/fields/WebField.ts @@ -24,7 +24,7 @@ export class WebField extends BasicField { type: Types.Web, data: this.Data.href, _id: this.Id - } + }; } } \ No newline at end of file diff --git a/src/mobile/ImageUpload.tsx b/src/mobile/ImageUpload.tsx index c3684a0eb..ec89a1194 100644 --- a/src/mobile/ImageUpload.tsx +++ b/src/mobile/ImageUpload.tsx @@ -22,7 +22,7 @@ import { Opt } from '../fields/Field'; // } const onFileLoad = async (file: any) => { - let imgPrev = document.getElementById("img_preview") + let imgPrev = document.getElementById("img_preview"); if (imgPrev) { let files: File[] = file.target.files; if (files.length !== 0) { @@ -30,15 +30,15 @@ const onFileLoad = async (file: any) => { let formData = new FormData(); formData.append("file", files[0]); - const upload = window.location.origin + "/upload" + const upload = window.location.origin + "/upload"; const res = await fetch(upload, { method: 'POST', body: formData }); const json = await res.json(); json.map(async (file: any) => { - let path = window.location.origin + file - var doc: Document = Documents.ImageDocument(path, { nativeWidth: 200, width: 200 }) + let path = window.location.origin + file; + var doc: Document = Documents.ImageDocument(path, { nativeWidth: 200, width: 200 }); const res = await rp.get(ServerUtils.prepend(RouteStore.getUserDocumentId)); if (!res) { @@ -47,12 +47,12 @@ const onFileLoad = async (file: any) => { const field = await Server.GetField(res); let pending: Opt; if (field instanceof Document) { - pending = await field.GetTAsync(KeyStore.OptionalRightCollection, Document) + pending = await field.GetTAsync(KeyStore.OptionalRightCollection, Document); } if (pending) { pending.GetOrCreateAsync(KeyStore.Data, ListField, list => { list.Data.push(doc); - }) + }); } }); @@ -61,7 +61,7 @@ const onFileLoad = async (file: any) => { //imgPrev.setAttribute("src", window.location.origin + files[0].name) } } -} +}; ReactDOM.render((
diff --git a/src/server/Client.ts b/src/server/Client.ts index 6b8841658..02402a5a0 100644 --- a/src/server/Client.ts +++ b/src/server/Client.ts @@ -2,14 +2,14 @@ import { computed } from "mobx"; export class Client { constructor(guid: string) { - this.guid = guid + this.guid = guid; } private guid: string; @computed public get GUID(): string { - return this.guid + return this.guid; } } \ No newline at end of file diff --git a/src/server/authentication/config/passport.ts b/src/server/authentication/config/passport.ts index b6fe15655..d42741410 100644 --- a/src/server/authentication/config/passport.ts +++ b/src/server/authentication/config/passport.ts @@ -1,4 +1,4 @@ -import * as passport from 'passport' +import * as passport from 'passport'; import * as passportLocal from 'passport-local'; import * as mongodb from 'mongodb'; import * as _ from "lodash"; @@ -22,7 +22,7 @@ passport.deserializeUser((id, done) => { passport.use(new LocalStrategy({ usernameField: 'email', passReqToCallback: true }, (req, email, password, done) => { User.findOne({ email: email.toLowerCase() }, (error: any, user: any) => { if (error) return done(error); - if (!user) return done(undefined, false, { message: "Invalid email or password" }) // invalid email + if (!user) return done(undefined, false, { message: "Invalid email or password" }); // invalid email user.comparePassword(password, (error: Error, isMatch: boolean) => { if (error) return done(error); if (!isMatch) return done(undefined, false, { message: "Invalid email or password" }); // invalid password @@ -37,7 +37,7 @@ export let isAuthenticated = (req: Request, res: Response, next: NextFunction) = return next(); } return res.redirect(RouteStore.login); -} +}; export let isAuthorized = (req: Request, res: Response, next: NextFunction) => { const provider = req.path.split("/").slice(-1)[0]; diff --git a/src/server/authentication/controllers/WorkspacesMenu.tsx b/src/server/authentication/controllers/WorkspacesMenu.tsx index 835432c8e..b08c1aebe 100644 --- a/src/server/authentication/controllers/WorkspacesMenu.tsx +++ b/src/server/authentication/controllers/WorkspacesMenu.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import { observable, action, configure, reaction, computed, ObservableMap, runInAction } from 'mobx'; import { observer } from "mobx-react"; -import './WorkspacesMenu.css' +import './WorkspacesMenu.css'; import { Document } from '../../../fields/Document'; import { EditableView } from '../../../client/views/EditableView'; import { KeyStore } from '../../../fields/KeyStore'; diff --git a/src/server/authentication/controllers/user_controller.ts b/src/server/authentication/controllers/user_controller.ts index 2bbb334b5..1dacdf3fa 100644 --- a/src/server/authentication/controllers/user_controller.ts +++ b/src/server/authentication/controllers/user_controller.ts @@ -109,12 +109,12 @@ export let postLogin = (req: Request, res: Response, next: NextFunction) => { } passport.authenticate("local", (err: Error, user: DashUserModel, info: IVerifyOptions) => { - if (err) { next(err); return } + if (err) { next(err); return; } if (!user) { return res.redirect(RouteStore.signup); } req.logIn(user, (err) => { - if (err) { next(err); return } + if (err) { next(err); return; } res.redirect(RouteStore.home); }); })(req, res, next); @@ -132,14 +132,14 @@ export let getLogout = (req: Request, res: Response) => { sess.destroy((err) => { if (err) { console.log(err); } }); } res.redirect(RouteStore.login); -} +}; export let getForgot = function (req: Request, res: Response) { res.render("forgot.pug", { title: "Recover Password", user: req.user, }); -} +}; export let postForgot = function (req: Request, res: Response, next: NextFunction) { const email = req.body.email; @@ -152,14 +152,14 @@ export let postForgot = function (req: Request, res: Response, next: NextFunctio return; } done(null, buffer.toString('hex')); - }) + }); }, function (token: string, done: any) { User.findOne({ email }, function (err, user: DashUserModel) { if (!user) { // NO ACCOUNT WITH SUBMITTED EMAIL res.redirect(RouteStore.forgot); - return + return; } user.passwordResetToken = token; user.passwordResetExpires = new Date(Date.now() + 3600000); // 1 HOUR @@ -193,8 +193,8 @@ export let postForgot = function (req: Request, res: Response, next: NextFunctio ], function (err) { if (err) return next(err); res.redirect(RouteStore.forgot); - }) -} + }); +}; export let getReset = function (req: Request, res: Response) { User.findOne({ passwordResetToken: req.params.token, passwordResetExpires: { $gt: Date.now() } }, function (err, user: DashUserModel) { @@ -206,7 +206,7 @@ export let getReset = function (req: Request, res: Response) { user: req.user, }); }); -} +}; export let postReset = function (req: Request, res: Response) { async.waterfall([ @@ -263,4 +263,4 @@ export let postReset = function (req: Request, res: Response) { ], function (err) { res.redirect(RouteStore.login); }); -} \ No newline at end of file +}; \ No newline at end of file diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index 0ac85b446..13eddafbf 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -70,7 +70,7 @@ export class CurrentUserUtils { let doc = new Document(id); doc.Set(KeyStore.Workspaces, new ListField()); - doc.Set(KeyStore.OptionalRightCollection, Documents.SchemaDocument([], { title: "Pending documents" })) + doc.Set(KeyStore.OptionalRightCollection, Documents.SchemaDocument([], { title: "Pending documents" })); return doc; } @@ -81,7 +81,7 @@ export class CurrentUserUtils { CurrentUserUtils.curr_id = obj.id as string; CurrentUserUtils.curr_email = obj.email as string; } else { - throw new Error("There should be a user! Why does Dash think there isn't one?") + throw new Error("There should be a user! Why does Dash think there isn't one?"); } }); let userDocPromise = rp.get(ServerUtils.prepend(RouteStore.getUserDocumentId)).then(id => { @@ -92,9 +92,9 @@ export class CurrentUserUtils { } else { this.user_document = this.createUserDocument(id); } - }) + }); } else { - throw new Error("There should be a user id! Why does Dash think there isn't one?") + throw new Error("There should be a user id! Why does Dash think there isn't one?"); } }); return Promise.all([userPromise, userDocPromise]); diff --git a/src/server/authentication/models/user_model.ts b/src/server/authentication/models/user_model.ts index 81580aad5..1c6926517 100644 --- a/src/server/authentication/models/user_model.ts +++ b/src/server/authentication/models/user_model.ts @@ -2,7 +2,7 @@ import * as bcrypt from "bcrypt-nodejs"; //@ts-ignore import * as mongoose from "mongoose"; -var url = 'mongodb://localhost:27017/Dash' +var url = 'mongodb://localhost:27017/Dash'; mongoose.connect(url, { useNewUrlParser: true }); diff --git a/src/server/database.ts b/src/server/database.ts index 415acc09a..0bc806253 100644 --- a/src/server/database.ts +++ b/src/server/database.ts @@ -1,15 +1,15 @@ import * as mongodb from 'mongodb'; export class Database { - public static Instance = new Database() + public static Instance = new Database(); private MongoClient = mongodb.MongoClient; private url = 'mongodb://localhost:27017/Dash'; private db?: mongodb.Db; constructor() { this.MongoClient.connect(this.url, (err, client) => { - this.db = client.db() - }) + this.db = client.db(); + }); } private currentWrites: { [_id: string]: Promise } = {}; @@ -30,19 +30,19 @@ export class Database { // console.log(JSON.stringify(res.result)); // } if (this.currentWrites[id] === promise) { - delete this.currentWrites[id] + delete this.currentWrites[id]; } if (resolve) { resolve(); } callback(); }); - } + }; if (prom) { const newProm: Promise = prom.then(() => run(newProm)); this.currentWrites[id] = newProm; } else { - const newProm: Promise = new Promise(res => run(newProm, res)) + const newProm: Promise = new Promise(res => run(newProm, res)); this.currentWrites[id] = newProm; } } @@ -61,7 +61,7 @@ export class Database { let collection = this.db.collection(collectionName); collection.deleteMany({}, res); } - }) + }); } public insert(kvpairs: any) { @@ -70,7 +70,7 @@ export class Database { collection.insertOne(kvpairs, (err: any, res: any) => { if (err) { // console.log(err) - return + return; } }); } @@ -81,30 +81,30 @@ export class Database { if (this.db) { let collection = this.db.collection('documents'); collection.findOne({ _id: id }, (err: any, res: any) => { - result = res + result = res; if (!result) { - fn(undefined) + fn(undefined); } - fn(result) - }) - }; + fn(result); + }); + } } public getDocuments(ids: string[], fn: (res: any) => void) { if (this.db) { let collection = this.db.collection('documents'); - let cursor = collection.find({ _id: { "$in": ids } }) + let cursor = collection.find({ _id: { "$in": ids } }); cursor.toArray((err, docs) => { if (err) { console.log(err.message); console.log(err.errmsg); } fn(docs); - }) - }; + }); + } } public print() { - console.log("db says hi!") + console.log("db says hi!"); } } diff --git a/src/server/index.ts b/src/server/index.ts index f60e6e293..b9c7448b4 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -1,10 +1,10 @@ -import * as express from 'express' -const app = express() -import * as webpack from 'webpack' +import * as express from 'express'; +const app = express(); +import * as webpack from 'webpack'; import * as wdm from 'webpack-dev-middleware'; import * as whm from 'webpack-hot-middleware'; -import * as path from 'path' -import * as formidable from 'formidable' +import * as path from 'path'; +import * as formidable from 'formidable'; import * as passport from 'passport'; import { MessageStore, Transferable } from "./Message"; import { Client } from './Client'; @@ -13,7 +13,7 @@ import { Utils } from '../Utils'; import { ObservableMap } from 'mobx'; import { FieldId, Field } from '../fields/Field'; import { Database } from './database'; -import * as io from 'socket.io' +import * as io from 'socket.io'; import { getLogin, postLogin, getSignup, postSignup, getLogout, postReset, getForgot, postForgot, getReset } from './authentication/controllers/user_controller'; const config = require('../../webpack.config'); const compiler = webpack(config); @@ -31,19 +31,19 @@ const MongoStore = require('connect-mongo')(session); const mongoose = require('mongoose'); import { DashUserModel } from './authentication/models/user_model'; import * as fs from 'fs'; -import * as request from 'request' +import * as request from 'request'; import { RouteStore } from './RouteStore'; -import { exec } from 'child_process' +import { exec } from 'child_process'; const download = (url: string, dest: fs.PathLike) => { request.get(url).pipe(fs.createWriteStream(dest)); -} +}; const mongoUrl = 'mongodb://localhost:27017/Dash'; -mongoose.connect(mongoUrl) +mongoose.connect(mongoUrl); mongoose.connection.on('connected', function () { console.log("connected"); -}) +}); // SESSION MANAGEMENT AND AUTHENTICATION MIDDLEWARE // ORDER OF IMPORTS MATTERS @@ -73,7 +73,7 @@ app.use((req, res, next) => { app.get("/hello", (req, res) => { res.send("

Hello

"); -}) +}); enum Method { GET, @@ -98,7 +98,7 @@ function addSecureRoute(method: Method, const dashUser: DashUserModel = req.user; if (!dashUser) return onRejection(res); handler(dashUser, res, req); - } + }; subscribers.forEach(route => { switch (method) { case Method.GET: @@ -116,7 +116,7 @@ function addSecureRoute(method: Method, let FieldStore: ObservableMap = new ObservableMap(); app.use(express.static(__dirname + RouteStore.public)); -app.use(RouteStore.images, express.static(__dirname + RouteStore.public)) +app.use(RouteStore.images, express.static(__dirname + RouteStore.public)); app.get("/pull", (req, res) => { exec('"C:\\Program Files\\Git\\git-bash.exe" -c "git pull"', (err, stdout, stderr) => { @@ -125,7 +125,7 @@ app.get("/pull", (req, res) => { return; } res.redirect("/"); - }) + }); }); // GETTERS @@ -178,13 +178,13 @@ addSecureRoute( addSecureRoute( Method.POST, (user, res, req) => { - let form = new formidable.IncomingForm() - form.uploadDir = __dirname + "/public/files/" - form.keepExtensions = true + let form = new formidable.IncomingForm(); + form.uploadDir = __dirname + "/public/files/"; + form.keepExtensions = true; // let path = req.body.path; - console.log("upload") + console.log("upload"); form.parse(req, (err, fields, files) => { - console.log("parsing") + console.log("parsing"); let names: any[] = []; for (const name in files) { let file = files[name]; @@ -211,8 +211,8 @@ app.post(RouteStore.login, postLogin); app.get(RouteStore.logout, getLogout); // FORGOT PASSWORD EMAIL HANDLING -app.get(RouteStore.forgot, getForgot) -app.post(RouteStore.forgot, postForgot) +app.get(RouteStore.forgot, getForgot); +app.post(RouteStore.forgot, postForgot); // RESET PASSWORD EMAIL HANDLING app.get(RouteStore.reset, getReset); @@ -232,32 +232,32 @@ app.get(RouteStore.deleteAll, (req, res) => { app.use(wdm(compiler, { publicPath: config.output.publicPath -})) +})); -app.use(whm(compiler)) +app.use(whm(compiler)); // start the Express server app.listen(port, () => { console.log(`server started at http://localhost:${port}`); -}) +}); const server = io(); interface Map { [key: string]: Client; } -let clients: Map = {} +let clients: Map = {}; server.on("connection", function (socket: Socket) { - console.log("a user has connected") + console.log("a user has connected"); - Utils.Emit(socket, MessageStore.Foo, "handshooken") + Utils.Emit(socket, MessageStore.Foo, "handshooken"); - Utils.AddServerHandler(socket, MessageStore.Bar, barReceived) - Utils.AddServerHandler(socket, MessageStore.SetField, (args) => setField(socket, args)) - Utils.AddServerHandlerCallback(socket, MessageStore.GetField, getField) - Utils.AddServerHandlerCallback(socket, MessageStore.GetFields, getFields) - Utils.AddServerHandler(socket, MessageStore.DeleteAll, deleteFields) -}) + Utils.AddServerHandler(socket, MessageStore.Bar, barReceived); + Utils.AddServerHandler(socket, MessageStore.SetField, (args) => setField(socket, args)); + Utils.AddServerHandlerCallback(socket, MessageStore.GetField, getField); + Utils.AddServerHandlerCallback(socket, MessageStore.GetFields, getFields); + Utils.AddServerHandler(socket, MessageStore.DeleteAll, deleteFields); +}); function deleteFields() { return Database.Instance.deleteAll(); @@ -276,12 +276,12 @@ function barReceived(guid: String) { function getField([id, callback]: [string, (result: any) => void]) { Database.Instance.getDocument(id, (result: any) => { if (result) { - callback(result) + callback(result); } else { - callback(undefined) + callback(undefined); } - }) + }); } function getFields([ids, callback]: [string[], (result: any) => void]) { @@ -291,7 +291,7 @@ function getFields([ids, callback]: [string[], (result: any) => void]) { function setField(socket: Socket, newValue: Transferable) { Database.Instance.update(newValue._id, newValue, () => { socket.broadcast.emit(MessageStore.SetField.Message, newValue); - }) + }); } server.listen(serverPort); diff --git a/test/test.ts b/test/test.ts index db24cae5f..16cace026 100644 --- a/test/test.ts +++ b/test/test.ts @@ -1,6 +1,6 @@ import { NumberField } from "../src/fields/NumberField"; import { expect } from 'chai'; -import 'mocha' +import 'mocha'; import { Key } from "../src/fields/Key"; import { Document } from "../src/fields/Document"; import { autorun, reaction } from "mobx"; @@ -17,7 +17,7 @@ describe('Number Controller', () => { it('Should update', () => { const numController = new NumberField(15); let ran = false; - reaction(() => numController.Data, (data) => { ran = true; }) + reaction(() => numController.Data, (data) => { ran = true; }); expect(ran).to.equal(false); numController.Data = 5; expect(ran).to.equal(true); @@ -42,7 +42,7 @@ describe("Document", () => { let key = new Key("Test"); let key2 = new Key("Test2"); let ran = false; - reaction(() => doc.Get(key), (field) => { ran = true }); + reaction(() => doc.Get(key), (field) => { ran = true; }); expect(ran).to.equal(false); doc.Set(key2, new NumberField(4)); diff --git a/tslint.json b/tslint.json index 54876916e..aa4dee4e5 100644 --- a/tslint.json +++ b/tslint.json @@ -27,14 +27,14 @@ "arrow-return-shorthand": true, // "object-literal-shorthand": true, // "object-literal-sort-keys": true, - // "semicolon": [ - // true, - // "always" - // ], - // "curly": [ - // true, - // "ignore-same-line" - // ], + "semicolon": [ + true, + "always" + ], + "curly": [ + true, + "ignore-same-line" + ], // "quotemark": [ // true, // "double", -- cgit v1.2.3-70-g09d2 From 64c8a689c142c82c4dd3ed074e5e6981ea8ea17c Mon Sep 17 00:00:00 2001 From: bob Date: Tue, 9 Apr 2019 13:40:40 -0400 Subject: added ability to load a new database for Northstar --- src/client/northstar/manager/Gateway.ts | 22 ++++++++++++++++++++-- src/client/views/Main.tsx | 15 ++++++++++----- .../views/collections/CollectionBaseView.tsx | 16 ++++++---------- src/client/views/collections/CollectionSubView.tsx | 2 +- 4 files changed, 37 insertions(+), 18 deletions(-) (limited to 'src/client/northstar') diff --git a/src/client/northstar/manager/Gateway.ts b/src/client/northstar/manager/Gateway.ts index 1c8d3fd73..8f3b6b11c 100644 --- a/src/client/northstar/manager/Gateway.ts +++ b/src/client/northstar/manager/Gateway.ts @@ -23,6 +23,17 @@ export class Gateway { } } + public async GetSchema(dbName: string): Promise { + try { + const json = await this.MakeGetRequest("schema", undefined, dbName); + const cat = Catalog.fromJS(json); + return cat; + } + catch (error) { + throw new Error("can not reach northstar's backend"); + } + } + public async ClearCatalog(): Promise { try { const json = await this.MakePostJsonRequest("Datamart/ClearAllAugmentations", {}); @@ -133,8 +144,15 @@ export class Gateway { }); } - public async MakeGetRequest(endpoint: string, signal?: AbortSignal): Promise { - const url = Gateway.ConstructUrl(endpoint); + public async MakeGetRequest(endpoint: string, signal?: AbortSignal, data?: any): Promise { + let url = !data ? Gateway.ConstructUrl(endpoint) : + (() => { + let newUrl = new URL(Gateway.ConstructUrl(endpoint)); + newUrl.searchParams.append("data", data); + return Gateway.ConstructUrl(endpoint) + newUrl.search; + return newUrl as any; + })(); + const response = await fetch(url, { redirect: "follow", diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index fd2e23c91..32798631d 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -348,10 +348,10 @@ export class Main extends React.Component { // --------------- Northstar hooks ------------- / - @action SetNorthstarCatalog(ctlog: Catalog) { - CurrentUserUtils.NorthstarDBCatalog = ctlog; + @action AddToNorthstarCatalog(ctlog: Catalog) { + CurrentUserUtils.NorthstarDBCatalog = CurrentUserUtils.NorthstarDBCatalog ? CurrentUserUtils.NorthstarDBCatalog : ctlog; if (ctlog && ctlog.schemas) { - this._northstarSchemas = ctlog.schemas.map(schema => { + this._northstarSchemas.push(...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 => { @@ -369,7 +369,7 @@ export class Main extends React.Component { })); }); return schemaDoc; - }); + })); } } async initializeNorthstar(): Promise { @@ -382,7 +382,12 @@ export class Main extends React.Component { const env = await response.json(); Settings.Instance.Update(env); let cat = Gateway.Instance.ClearCatalog(); - cat.then(async () => this.SetNorthstarCatalog(await Gateway.Instance.GetCatalog())); + cat.then(async () => { + this.AddToNorthstarCatalog(await Gateway.Instance.GetCatalog()); + if (!CurrentUserUtils.GetNorthstarSchema("Book1")) + this.AddToNorthstarCatalog(await Gateway.Instance.GetSchema("http://www.cs.brown.edu/~bcz/Book1.csv")); + }); + } } diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx index 4afa7cbf6..4380c8194 100644 --- a/src/client/views/collections/CollectionBaseView.tsx +++ b/src/client/views/collections/CollectionBaseView.tsx @@ -1,17 +1,13 @@ +import { action } from 'mobx'; +import { observer } from 'mobx-react'; import * as React from 'react'; -import { FieldViewProps } from '../nodes/FieldView'; +import { Document } from '../../../fields/Document'; +import { Field, FieldValue, FieldWaiting } from '../../../fields/Field'; import { KeyStore } from '../../../fields/KeyStore'; +import { ListField } from '../../../fields/ListField'; import { NumberField } from '../../../fields/NumberField'; -import { FieldWaiting, Field, FieldValue } from '../../../fields/Field'; import { ContextMenu } from '../ContextMenu'; -import { SelectionManager } from '../../util/SelectionManager'; -import { Document } from '../../../fields/Document'; -import { ListField } from '../../../fields/ListField'; -import { action } from 'mobx'; -import { Transform } from '../../util/Transform'; -import { observer } from 'mobx-react'; -import { CompileScript } from '../../util/Scripting'; -import { ScriptField } from '../../../fields/ScriptField'; +import { FieldViewProps } from '../nodes/FieldView'; export enum CollectionViewType { Invalid, diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index f058aaccc..5cdea0568 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -73,7 +73,7 @@ export class CollectionSubView extends React.Component { draggedDocument.GetTAsync(key, NumberField, (f: Opt) => f ? de.data.droppedDocuments[i].SetNumber(key, f.Data) : null))); } let added = false; - if (de.data.aliasOnDrop) { + if (de.data.aliasOnDrop || de.data.copyOnDrop) { added = de.data.droppedDocuments.reduce((added: boolean, d) => added || this.props.addDocument(d), false); } else if (de.data.moveDocument) { const move = de.data.moveDocument; -- cgit v1.2.3-70-g09d2 From 9ea0f409cfc2a6c11bb1cf6e00015eb97900507b Mon Sep 17 00:00:00 2001 From: bob Date: Wed, 10 Apr 2019 10:45:59 -0400 Subject: fixed uploading of csv files. --- src/client/documents/Documents.ts | 39 +++++++++++++++++++-- src/client/northstar/manager/Gateway.ts | 12 +++---- src/client/views/Main.tsx | 4 +-- src/client/views/collections/CollectionSubView.tsx | 40 +++++++++++++--------- src/fields/KeyStore.ts | 1 - 5 files changed, 68 insertions(+), 28 deletions(-) (limited to 'src/client/northstar') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 72e6e57ab..f8438e093 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 } from "../../fields/Field"; +import { Field, Opt } from "../../fields/Field"; import { HtmlField } from "../../fields/HtmlField"; import { ImageField } from "../../fields/ImageField"; import { InkField, StrokeData } from "../../fields/InkField"; @@ -26,6 +26,12 @@ 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 { Gateway } from "../northstar/manager/Gateway"; +import { CurrentUserUtils } from "../../server/authentication/models/current_user_utils"; +import { action } from "mobx"; +import { ColumnAttributeModel } from "../northstar/core/attribute/AttributeModel"; +import { AttributeTransformationModel } from "../northstar/core/attribute/AttributeTransformationModel"; +import { AggregateFunction } from "../northstar/model/idea/idea"; export interface DocumentOptions { x?: number; @@ -200,6 +206,31 @@ export namespace Documents { export function PdfDocument(url: string, options: DocumentOptions = {}) { return assignToDelegate(SetInstanceOptions(pdfProto, options, [new URL(url), PDFField]).MakeDelegate(), options); } + export async function DBDocument(url: string, options: DocumentOptions = {}) { + let schemaName = options.title ? options.title : "-no schema-"; + let ctlog = await Gateway.Instance.GetSchema(url, schemaName) + if (ctlog && ctlog.schemas) { + let schema = ctlog.schemas[0]; + let schemaDoc = Documents.TreeDocument([], { ...options, nativeWidth: undefined, nativeHeight: undefined, width: 150, height: 100, title: schema.displayName! }); + let schemaDocuments = schemaDoc.GetList(KeyStore.Data, [] as Document[]); + CurrentUserUtils.GetAllNorthstarColumnAttributes(schema).map(attr => { + Server.GetField(attr.displayName! + ".alias", 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! }, undefined, attr.displayName! + ".alias")); + } + })); + }); + return schemaDoc; + }; + return Documents.TreeDocument([], { width: 50, height: 100, title: schemaName }); + } export function WebDocument(url: string, options: DocumentOptions = {}) { return assignToDelegate(SetInstanceOptions(webProto, options, [new URL(url), WebField]).MakeDelegate(), options); } @@ -242,13 +273,15 @@ export namespace Documents {
` + FormattedTextBox.LayoutString("CaptionKey") + `
-
`; } + `; + } export function FixedCaption(fieldName: string = "Caption") { return `
` + FormattedTextBox.LayoutString(fieldName + "Key") + `
-
`; } + `; + } function OuterCaption() { return (` diff --git a/src/client/northstar/manager/Gateway.ts b/src/client/northstar/manager/Gateway.ts index 8f3b6b11c..207a9ad19 100644 --- a/src/client/northstar/manager/Gateway.ts +++ b/src/client/northstar/manager/Gateway.ts @@ -23,9 +23,9 @@ export class Gateway { } } - public async GetSchema(dbName: string): Promise { + public async GetSchema(pathname: string, schemaname: string): Promise { try { - const json = await this.MakeGetRequest("schema", undefined, dbName); + const json = await this.MakeGetRequest("schema", undefined, { path: pathname, schema: schemaname }); const cat = Catalog.fromJS(json); return cat; } @@ -144,13 +144,13 @@ export class Gateway { }); } - public async MakeGetRequest(endpoint: string, signal?: AbortSignal, data?: any): Promise { - let url = !data ? Gateway.ConstructUrl(endpoint) : + public async MakeGetRequest(endpoint: string, signal?: AbortSignal, params?: any): Promise { + let url = !params ? Gateway.ConstructUrl(endpoint) : (() => { let newUrl = new URL(Gateway.ConstructUrl(endpoint)); - newUrl.searchParams.append("data", data); + Object.getOwnPropertyNames(params).map(prop => + newUrl.searchParams.append(prop, params[prop])); return Gateway.ConstructUrl(endpoint) + newUrl.search; - return newUrl as any; })(); const response = await fetch(url, diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index 32798631d..012633bed 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -384,8 +384,8 @@ export class Main extends React.Component { let cat = Gateway.Instance.ClearCatalog(); cat.then(async () => { this.AddToNorthstarCatalog(await Gateway.Instance.GetCatalog()); - if (!CurrentUserUtils.GetNorthstarSchema("Book1")) - this.AddToNorthstarCatalog(await Gateway.Instance.GetSchema("http://www.cs.brown.edu/~bcz/Book1.csv")); + // if (!CurrentUserUtils.GetNorthstarSchema("Book1")) + // this.AddToNorthstarCatalog(await Gateway.Instance.GetSchema("http://www.cs.brown.edu/~bcz/Book1.csv", "Book1")); }); } diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 5cdea0568..588ff9483 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -87,8 +87,8 @@ export class CollectionSubView extends React.Component { return false; } - protected getDocumentFromType(type: string, path: string, options: DocumentOptions): Opt { - let ctor: ((path: string, options: DocumentOptions) => Document) | undefined; + protected async getDocumentFromType(type: string, path: string, options: DocumentOptions): Promise> { + let ctor: ((path: string, options: DocumentOptions) => (Document | Promise)) | undefined = undefined; if (type.indexOf("image") !== -1) { ctor = Documents.ImageDocument; } @@ -102,6 +102,10 @@ export class CollectionSubView extends React.Component { ctor = Documents.PdfDocument; options.nativeWidth = 1200; } + if (type.indexOf("excel") !== -1) { + ctor = Documents.DBDocument; + options.copyDraggedItems = true; + } if (type.indexOf("html") !== -1) { if (path.includes('localhost')) { let s = path.split('/'); @@ -159,10 +163,11 @@ export class CollectionSubView extends React.Component { })).then(res => { let type = res.headers["content-type"]; if (type) { - let doc = this.getDocumentFromType(type, str, { ...options, width: 300, nativeWidth: 300 }); - if (doc) { - this.props.addDocument(doc, false); - } + this.getDocumentFromType(type, str, { ...options, width: 300, nativeWidth: 300 }).then(doc => { + if (doc) { + this.props.addDocument(doc, false); + } + }); } }); promises.push(prom); @@ -176,6 +181,7 @@ export class CollectionSubView extends React.Component { if (file) { formData.append('file', file); } + let dropFileName = file ? file.name : "-empty-"; let prom = fetch(upload, { method: 'POST', @@ -185,18 +191,20 @@ export class CollectionSubView extends React.Component { json.map((file: any) => { let path = window.location.origin + file; runInAction(() => { - let doc = this.getDocumentFromType(type, path, { ...options, nativeWidth: 300, width: 300 }); + let docPromise = this.getDocumentFromType(type, path, { ...options, nativeWidth: 300, width: 300, title: dropFileName }); - let docs = this.props.Document.GetT(KeyStore.Data, ListField); - if (docs !== FieldWaiting) { - if (!docs) { - docs = new ListField(); - this.props.Document.Set(KeyStore.Data, docs); - } - if (doc) { - docs.Data.push(doc); + docPromise.then(doc => runInAction(() => { + let docs = this.props.Document.GetT(KeyStore.Data, ListField); + if (docs !== FieldWaiting) { + if (!docs) { + docs = new ListField(); + this.props.Document.Set(KeyStore.Data, docs); + } + if (doc) { + docs.Data.push(doc); + } } - } + })); }); }); }); diff --git a/src/fields/KeyStore.ts b/src/fields/KeyStore.ts index 425408273..da2d7268f 100644 --- a/src/fields/KeyStore.ts +++ b/src/fields/KeyStore.ts @@ -1,5 +1,4 @@ import { Key } from "./Key"; -import { KeyTransfer } from "../server/Message"; export namespace KeyStore { export const Prototype = new Key("Prototype"); -- cgit v1.2.3-70-g09d2 From e0b3c759880639bf56f9b8b39ea2e38c5cbad8a6 Mon Sep 17 00:00:00 2001 From: bob Date: Wed, 10 Apr 2019 14:28:25 -0400 Subject: fixed extra rendering for collections. --- src/client/Server.ts | 10 +++---- .../dash-nodes/HistogramBoxPrimitives.tsx | 6 ++-- src/client/util/DragManager.ts | 4 +-- src/client/util/SelectionManager.ts | 2 +- src/client/views/DocumentDecorations.tsx | 5 ++-- src/client/views/Main.scss | 24 +++++++-------- src/client/views/Main.tsx | 19 ++++++++---- .../views/collections/CollectionDockingView.tsx | 4 +-- src/client/views/collections/CollectionPDFView.tsx | 3 +- .../views/collections/CollectionSchemaView.tsx | 4 +-- src/client/views/collections/CollectionSubView.tsx | 3 +- .../views/collections/CollectionVideoView.tsx | 3 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 7 +++-- src/client/views/nodes/DocumentView.tsx | 35 ++++++++++++++-------- src/client/views/nodes/FieldView.tsx | 10 +++---- src/client/views/nodes/FormattedTextBox.tsx | 4 +-- src/client/views/nodes/VideoBox.tsx | 2 +- 17 files changed, 84 insertions(+), 61 deletions(-) (limited to 'src/client/northstar') diff --git a/src/client/Server.ts b/src/client/Server.ts index 857101a33..228d94a7b 100644 --- a/src/client/Server.ts +++ b/src/client/Server.ts @@ -1,10 +1,10 @@ import { Key } from "../fields/Key"; -import { ObservableMap, action, reaction } from "mobx"; +import { ObservableMap, action, reaction, runInAction } from "mobx"; import { Field, FieldWaiting, FIELD_WAITING, Opt, FieldId } from "../fields/Field"; import { Document } from "../fields/Document"; import { SocketStub, FieldMap } from "./SocketStub"; import * as OpenSocket from 'socket.io-client'; -import { Utils } from "./../Utils"; +import { Utils, emptyFunction } from "./../Utils"; import { MessageStore, Types } from "./../server/Message"; export class Server { @@ -59,7 +59,7 @@ export class Server { public static GetFields(fieldIds: FieldId[]): Promise<{ [id: string]: Field }>; public static GetFields(fieldIds: FieldId[], callback: (fields: FieldMap) => any): void; public static GetFields(fieldIds: FieldId[], callback?: (fields: FieldMap) => any): Promise | void { - let fn = (cb: (fields: FieldMap) => void) => { + let fn = (cb: (fields: FieldMap) => void) => runInAction(() => { let neededFieldIds: FieldId[] = []; let waitingFieldIds: FieldId[] = []; @@ -104,7 +104,7 @@ export class Server { } }, { fireImmediately: true }); })); - }; + }); if (callback) { fn(callback); } else { @@ -167,7 +167,7 @@ export class Server { if (f) { // console.log("Applying : " + field._id); f.UpdateFromServer(field.data); - f.init(() => { }); + f.init(emptyFunction); } else { // console.log("Not applying wa : " + field._id); } diff --git a/src/client/northstar/dash-nodes/HistogramBoxPrimitives.tsx b/src/client/northstar/dash-nodes/HistogramBoxPrimitives.tsx index 4c5bdb14b..721bf6a89 100644 --- a/src/client/northstar/dash-nodes/HistogramBoxPrimitives.tsx +++ b/src/client/northstar/dash-nodes/HistogramBoxPrimitives.tsx @@ -1,7 +1,7 @@ import React = require("react"); import { computed, observable, reaction, runInAction, trace, action } from "mobx"; import { observer } from "mobx-react"; -import { Utils as DashUtils } from '../../../Utils'; +import { Utils as DashUtils, emptyFunction } from '../../../Utils'; import { FilterModel } from "../../northstar/core/filter/FilterModel"; import { ModelHelpers } from "../../northstar/model/ModelHelpers"; import { ArrayUtil } from "../../northstar/utils/ArrayUtil"; @@ -49,7 +49,7 @@ export class HistogramBoxPrimitives extends React.Component bp.BrushIndex === allBrushIndex); if (!rawAllBrushPrim) { - return () => { }; + return emptyFunction; } let allBrushPrim = rawAllBrushPrim; return () => runInAction(() => { @@ -97,7 +97,7 @@ export class HistogramBoxPrimitives extends React.Component; } - drawRect(r: PIXIRectangle, barAxis: number, color: number | undefined, classExt: string, tapHandler: () => void = () => { }) { + drawRect(r: PIXIRectangle, barAxis: number, color: number | undefined, classExt: string, tapHandler: () => void = emptyFunction) { if (r.height < 0) { r.y += r.height; r.height = -r.height; diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 4849ae9f7..f7395578f 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -4,7 +4,7 @@ import { CollectionDockingView } from "../views/collections/CollectionDockingVie import { CollectionView } from "../views/collections/CollectionView"; import { DocumentDecorations } from "../views/DocumentDecorations"; import { DocumentView } from "../views/nodes/DocumentView"; -import { returnFalse } from "../../Utils"; +import { returnFalse, emptyFunction } from "../../Utils"; export function setupDrag(_reference: React.RefObject, docFunc: () => Document, moveFunc?: DragManager.MoveFunction, copyOnDrop: boolean = false) { let onRowMove = action((e: PointerEvent): void => { @@ -224,7 +224,7 @@ export namespace DragManager { CollectionDockingView.Instance.StartOtherDrag(docs, { pageX: e.pageX, pageY: e.pageY, - preventDefault: () => { }, + preventDefault: emptyFunction, button: 0 }); } diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts index 5ddaafc72..c6b8c7b0d 100644 --- a/src/client/util/SelectionManager.ts +++ b/src/client/util/SelectionManager.ts @@ -48,7 +48,7 @@ export namespace SelectionManager { manager.DeselectAll(); if (found) manager.SelectDoc(found, false); - Main.Instance.SetTextDoc(undefined, undefined); + Main.Instance.SetTextDoc(undefined, undefined, undefined); } export function SelectedDocuments(): Array { diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 28af46358..b7bf727f1 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -15,6 +15,7 @@ import { DocumentView } from "./nodes/DocumentView"; import { LinkMenu } from "./nodes/LinkMenu"; import React = require("react"); import { FieldWaiting } from "../../fields/Field"; +import { emptyFunction } from "../../Utils"; const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; @@ -217,7 +218,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> let dragData = new DragManager.LinkDragData(SelectionManager.SelectedDocuments()[0]); DragManager.StartLinkDrag(this._linkerButton.current, dragData, e.pageX, e.pageY, { handlers: { - dragComplete: action(() => { }), + dragComplete: action(emptyFunction), }, hideSource: false }); @@ -262,7 +263,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> let dragData = new DragManager.DocumentDragData(moddrag.length ? moddrag : draggedDocs); DragManager.StartDocumentDrag([this._linkButton.current], dragData, e.x, e.y, { handlers: { - dragComplete: action(() => { }), + dragComplete: action(emptyFunction), }, hideSource: false }); diff --git a/src/client/views/Main.scss b/src/client/views/Main.scss index fe7f007b0..8ef6b83f1 100644 --- a/src/client/views/Main.scss +++ b/src/client/views/Main.scss @@ -169,21 +169,21 @@ button:hover { overflow: scroll; } .mainDiv-textInput { - background:pink; - width: 200px; - height: 200px; + background-color: rgba(248, 6, 6, 0.1); + width: 200px; + height: 200px; + position:absolute; + overflow: visible; + top: 0; + left: 0; + .formattedTextBox-cont { + background-color: rgba(248, 6, 6, 0.1); + width: 100%; + height: 100%; position:absolute; - overflow: visible; top: 0; left: 0; - .formattedTextBox-cont { - background:pink; - width: 100%; - height: 100%; - position:absolute; - top: 0; - left: 0; - } +} } #mainContent-div { width:100%; diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index 012633bed..2751b1899 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -23,7 +23,7 @@ import { Documents } from '../documents/Documents'; import { ColumnAttributeModel } from '../northstar/core/attribute/AttributeModel'; import { AttributeTransformationModel } from '../northstar/core/attribute/AttributeTransformationModel'; import { Gateway, Settings } from '../northstar/manager/Gateway'; -import { AggregateFunction, Catalog } from '../northstar/model/idea/idea'; +import { AggregateFunction, Catalog, Point } from '../northstar/model/idea/idea'; import '../northstar/model/ModelExtensions'; import { HistogramOperation } from '../northstar/operations/HistogramOperation'; import '../northstar/utils/Extensions'; @@ -204,10 +204,12 @@ export class Main extends React.Component { @observable _textDoc?: Document = undefined; _textRect: any; + _textXf: Transform = Transform.Identity(); @action - SetTextDoc(textDoc?: Document, div?: HTMLDivElement) { + SetTextDoc(textDoc?: Document, div?: HTMLDivElement, tx?: Transform) { this._textDoc = undefined; this._textDoc = textDoc; + this._textXf = tx ? tx : Transform.Identity(); if (div) { this._textRect = div.getBoundingClientRect(); } @@ -220,8 +222,15 @@ export class Main extends React.Component { let y: number = this._textRect.y; let w: number = this._textRect.width; let h: number = this._textRect.height; - return
- { }} /> + let t = this._textXf.transformPoint(0, 0); + let s = this._textXf.transformPoint(1, 0); + s[0] = Math.sqrt((s[0] - t[0]) * (s[0] - t[0]) + (s[1] - t[1]) * (s[1] - t[1])); + return
+
+ + { }} /> + +
; } else return (null); @@ -310,7 +319,7 @@ export class Main extends React.Component {
,
-
+
]; } diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index ea6d3a247..212cf8a69 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -50,7 +50,7 @@ export class CollectionDockingView extends React.Component this.AddRightSplit(dragDoc, true).contentItems[0].tab._dragListener. - onMouseDown({ pageX: e.pageX, pageY: e.pageY, preventDefault: () => { }, button: 0 })); + onMouseDown({ pageX: e.pageX, pageY: e.pageY, preventDefault: emptyFunction, button: 0 })); } @action @@ -204,7 +204,7 @@ export class CollectionDockingView extends React.Component { }), + dragComplete: action(emptyFunction), }, hideSource: false }); diff --git a/src/client/views/collections/CollectionPDFView.tsx b/src/client/views/collections/CollectionPDFView.tsx index 97bac745c..6cbe59012 100644 --- a/src/client/views/collections/CollectionPDFView.tsx +++ b/src/client/views/collections/CollectionPDFView.tsx @@ -7,6 +7,7 @@ import React = require("react"); import { CollectionFreeFormView } from "./collectionFreeForm/CollectionFreeFormView"; import { FieldView, FieldViewProps } from "../nodes/FieldView"; import { CollectionRenderProps, CollectionBaseView, CollectionViewType } from "./CollectionBaseView"; +import { emptyFunction } from "../../../Utils"; @observer @@ -33,7 +34,7 @@ export class CollectionPDFView extends React.Component { onContextMenu = (e: React.MouseEvent): void => { if (!e.isPropagationStopped() && this.props.Document.Id !== "mainDoc") { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 - ContextMenu.Instance.addItem({ description: "PDFOptions", event: () => { } }); + ContextMenu.Instance.addItem({ description: "PDFOptions", event: emptyFunction }); } } diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index 587f60b3d..c67f8cd97 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -77,8 +77,8 @@ export class CollectionSchemaView extends CollectionSubView { let props: FieldViewProps = { Document: rowProps.value[0], fieldKey: rowProps.value[1], - isSelected: () => false, - select: () => { }, + isSelected: returnFalse, + select: emptyFunction, isTopMost: false, selectOnLoad: false, ScreenToLocalTransform: Transform.Identity, diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 588ff9483..ef0684955 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -15,6 +15,7 @@ import { ServerUtils } from "../../../server/ServerUtil"; import { Server } from "../../Server"; import { FieldViewProps } from "../nodes/FieldView"; import * as rp from 'request-promise'; +import { emptyFunction } from "../../../Utils"; export interface CollectionViewProps extends FieldViewProps { addDocument: (document: Document, allowDuplicates?: boolean) => boolean; @@ -213,7 +214,7 @@ export class CollectionSubView extends React.Component { } if (promises.length) { - Promise.all(promises).catch(() => { }).then(() => batch.end()); + Promise.all(promises).catch(emptyFunction).then(() => batch.end()); } else { batch.end(); } diff --git a/src/client/views/collections/CollectionVideoView.tsx b/src/client/views/collections/CollectionVideoView.tsx index b02983a2e..6c9780adb 100644 --- a/src/client/views/collections/CollectionVideoView.tsx +++ b/src/client/views/collections/CollectionVideoView.tsx @@ -7,6 +7,7 @@ import React = require("react"); import "./CollectionVideoView.scss"; import { CollectionFreeFormView } from "./collectionFreeForm/CollectionFreeFormView"; import { FieldView, FieldViewProps } from "../nodes/FieldView"; +import { emptyFunction } from "../../../Utils"; @observer @@ -100,7 +101,7 @@ export class CollectionVideoView extends React.Component { onContextMenu = (e: React.MouseEvent): void => { if (!e.isPropagationStopped() && this.props.Document.Id !== "mainDoc") { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 - ContextMenu.Instance.addItem({ description: "VideoOptions", event: () => { } }); + ContextMenu.Instance.addItem({ description: "VideoOptions", event: emptyFunction }); } } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 1feb30db1..102455d27 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -25,6 +25,7 @@ import { SelectionManager } from "../../../util/SelectionManager"; import { NumberField } from "../../../../fields/NumberField"; import { Main } from "../../Main"; import Measure from "react-measure"; +import { returnFalse, emptyFunction } from "../../../../Utils"; @observer export class CollectionFreeFormView extends CollectionSubView { @@ -200,7 +201,7 @@ export class CollectionFreeFormView extends CollectionSubView { @action private SetPan(panX: number, panY: number) { - Main.Instance.SetTextDoc(undefined, undefined); + Main.Instance.SetTextDoc(undefined, undefined, undefined); var x1 = this.getLocalTransform().inverse().Scale; const newPanX = Math.min((1 - 1 / x1) * this.nativeWidth, Math.max(0, panX)); const newPanY = Math.min((1 - 1 / x1) * this.nativeHeight, Math.max(0, panY)); @@ -290,13 +291,13 @@ export class CollectionFreeFormView extends CollectionSubView { get backgroundView() { return !this.backgroundLayout ? (null) : ( false} select={() => { }} />); + layoutKey={KeyStore.BackgroundLayout} isTopMost={this.props.isTopMost} isSelected={returnFalse} select={emptyFunction} />); } @computed get overlayView() { return !this.overlayLayout ? (null) : ( false} select={() => { }} />); + layoutKey={KeyStore.OverlayLayout} isTopMost={this.props.isTopMost} isSelected={returnFalse} select={emptyFunction} />); } getTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-COLLECTION_BORDER_WIDTH, -COLLECTION_BORDER_WIDTH).translate(-this.centeringShiftX, -this.centeringShiftY).transform(this.getLocalTransform()); diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 9670ca6b2..42967eb22 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -1,4 +1,4 @@ -import { action, computed, IReactionDisposer, reaction, runInAction } from "mobx"; +import { action, computed, IReactionDisposer, reaction, runInAction, trace } from "mobx"; import { observer } from "mobx-react"; import { Document } from "../../../fields/Document"; import { Field, FieldWaiting, Opt } from "../../../fields/Field"; @@ -8,7 +8,7 @@ import { ListField } from "../../../fields/ListField"; import { BooleanField } from "../../../fields/BooleanField"; import { TextField } from "../../../fields/TextField"; import { ServerUtils } from "../../../server/ServerUtil"; -import { Utils } from "../../../Utils"; +import { Utils, emptyFunction } from "../../../Utils"; import { Documents } from "../../documents/Documents"; import { DocumentManager } from "../../util/DocumentManager"; import { DragManager } from "../../util/DragManager"; @@ -62,12 +62,12 @@ export function FakeJsxArgs(keys: string[], fields: string[] = []): JsxArgs { let Keys: { [name: string]: any } = {}; let Fields: { [name: string]: any } = {}; for (const key of keys) { - let fn = () => { }; + let fn = emptyFunction; Object.defineProperty(fn, "name", { value: key + "Key" }); Keys[key] = fn; } for (const field of fields) { - let fn = () => { }; + let fn = emptyFunction; Object.defineProperty(fn, "name", { value: field }); Fields[field] = fn; } @@ -157,7 +157,7 @@ export class DocumentView extends React.Component { dragData.moveDocument = this.props.moveDocument; DragManager.StartDocumentDrag([this._mainCont.current], dragData, x, y, { handlers: { - dragComplete: action(() => { }) + dragComplete: action(emptyFunction) }, hideSource: !dropAliasOfDraggedDoc }); @@ -377,14 +377,28 @@ export class DocumentView extends React.Component { SelectionManager.SelectDoc(this, ctrlPressed); } + @computed get nativeWidth(): number { return this.props.Document.GetNumber(KeyStore.NativeWidth, 0); } + @computed get nativeHeight(): number { return this.props.Document.GetNumber(KeyStore.NativeHeight, 0); } + @computed + get contents() { + trace(); + return (); + } + render() { if (!this.props.Document) { return null; } + trace(); var scaling = this.props.ContentScaling(); - var nativeWidth = this.props.Document.GetNumber(KeyStore.NativeWidth, 0); - var nativeHeight = this.props.Document.GetNumber(KeyStore.NativeHeight, 0); + var nativeWidth = this.nativeWidth; + var nativeHeight = this.nativeHeight; if (this.isMinimized()) { return ( @@ -420,12 +434,7 @@ export class DocumentView extends React.Component { onContextMenu={this.onContextMenu} onPointerDown={this.onPointerDown} > - + {this.contents}
); } diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index 07c5b332c..40b44aae5 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -19,7 +19,7 @@ import { ListField } from "../../../fields/ListField"; import { DocumentContentsView } from "./DocumentContentsView"; import { Transform } from "../../util/Transform"; import { KeyStore } from "../../../fields/KeyStore"; -import { returnFalse } from "../../../Utils"; +import { returnFalse, emptyFunction } from "../../../Utils"; // @@ -85,9 +85,9 @@ export class FieldView extends React.Component { PanelHeight={() => 100} isTopMost={true} //TODO Why is this top most? selectOnLoad={false} - focus={() => { }} - isSelected={() => false} - select={() => false} + focus={emptyFunction} + isSelected={returnFalse} + select={returnFalse} layoutKey={KeyStore.Layout} ContainingCollectionView={undefined} parentActive={this.props.active} @@ -111,7 +111,7 @@ export class FieldView extends React.Component { } else { return

{"Waiting for server..."}

; - } + } } } \ No newline at end of file diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index beca6cdc6..bb1bc4fb0 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -161,13 +161,13 @@ export class FormattedTextBox extends React.Component { } if (this.props.fieldKey !== KeyStore.Archives) { e.preventDefault(); - Main.Instance.SetTextDoc(this.props.Document, this._ref.current!); + Main.Instance.SetTextDoc(this.props.Document, this._ref.current!, this.props.ScreenToLocalTransform()); } } onFocused = (e: React.FocusEvent): void => { if (this.props.fieldKey !== KeyStore.Archives) { - Main.Instance.SetTextDoc(this.props.Document, this._ref.current!); + Main.Instance.SetTextDoc(this.props.Document, this._ref.current!, this.props.ScreenToLocalTransform()); } } diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index 314af64c9..9d7c2bc56 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -66,7 +66,7 @@ export class VideoBox extends React.Component { {({ measureRef }) =>
-
,
]; } + @computed + get workspaceMenu() { + let areWorkspacesShown = () => this._workspacesShown; + let toggleWorkspaces = () => runInAction(() => { this._workspacesShown = !this._workspacesShown; }); + let workspaces = CurrentUserUtils.UserDocument.GetT>(KeyStore.Workspaces, ListField); + return (!workspaces || workspaces === FieldWaiting) ? (null) : + ; + } + render() { - let workspaceMenu: any = null; - let workspaces = this.userDocument.GetT>(KeyStore.Workspaces, ListField); - if (workspaces && workspaces !== FieldWaiting) { - workspaceMenu = ; - } return ( - <> -
- - runInAction(() => { - this.pwidth = r.entry.width; - this.pheight = r.entry.height; - })}> - {({ measureRef }) => -
- {this.mainContent} - -
- } -
- - {this.nodesMenu} - {this.miscButtons} - {workspaceMenu} - -
- {this.activeTextBox} - +
+ + {this.mainContent} + + + {this.nodesMenu} + {this.miscButtons} + {this.workspaceMenu} + + +
); } // --------------- Northstar hooks ------------- / + private _northstarSchemas: Document[] = []; - @action AddToNorthstarCatalog(ctlog: Catalog) { - CurrentUserUtils.NorthstarDBCatalog = CurrentUserUtils.NorthstarDBCatalog ? CurrentUserUtils.NorthstarDBCatalog : ctlog; + @action SetNorthstarCatalog(ctlog: Catalog) { + CurrentUserUtils.NorthstarDBCatalog = ctlog; if (ctlog && ctlog.schemas) { ctlog.schemas.map(schema => { - let promises: Promise[] = []; let schemaDocuments: Document[] = []; - CurrentUserUtils.GetAllNorthstarColumnAttributes(schema).map(attr => { - let prom = Server.GetField(attr.displayName! + ".alias").then(action((field: Opt) => { + let attributesToBecomeDocs = CurrentUserUtils.GetAllNorthstarColumnAttributes(schema); + Promise.all(attributesToBecomeDocs.reduce((promises, attr) => { + promises.push(Server.GetField(attr.displayName! + ".alias").then(action((field: Opt) => { if (field instanceof Document) { schemaDocuments.push(field); } else { @@ -430,32 +322,17 @@ export class Main extends React.Component { new AttributeTransformationModel(atmod, AggregateFunction.Count)); schemaDocuments.push(Documents.HistogramDocument(histoOp, { width: 200, height: 200, title: attr.displayName! }, undefined, attr.displayName! + ".alias")); } - })); - promises.push(prom); - }); - Promise.all(promises).finally(() => { - let schemaDoc = Documents.TreeDocument(schemaDocuments, { width: 50, height: 100, title: schema.displayName! }); - this._northstarSchemas.push(schemaDoc); - }); + }))); + return promises; + }, [] as Promise[])).finally(() => + this._northstarSchemas.push(Documents.TreeDocument(schemaDocuments, { width: 50, height: 100, title: schema.displayName! }))); }); } } async initializeNorthstar(): Promise { - let envPath = "/assets/env.json"; - const response = await fetch(envPath, { - redirect: "follow", - method: "GET", - credentials: "include" - }); - const env = await response.json(); - Settings.Instance.Update(env); - let cat = Gateway.Instance.ClearCatalog(); - cat.then(async () => { - this.AddToNorthstarCatalog(await Gateway.Instance.GetCatalog()); - // if (!CurrentUserUtils.GetNorthstarSchema("Book1")) - // this.AddToNorthstarCatalog(await Gateway.Instance.GetSchema("http://www.cs.brown.edu/~bcz/Book1.csv", "Book1")); - }); - + const getEnvironment = await fetch("/assets/env.json", { redirect: "follow", method: "GET", credentials: "include" }); + NorthstarSettings.Instance.UpdateEnvironment(await getEnvironment.json()); + Gateway.Instance.ClearCatalog().then(async () => this.SetNorthstarCatalog(await Gateway.Instance.GetCatalog())); } } diff --git a/src/client/views/MainOverlayTextBox.scss b/src/client/views/MainOverlayTextBox.scss new file mode 100644 index 000000000..697d68c8c --- /dev/null +++ b/src/client/views/MainOverlayTextBox.scss @@ -0,0 +1,19 @@ +@import "globalCssVariables"; +.mainOverlayTextBox-textInput { + background-color: rgba(248, 6, 6, 0.001); + width: 200px; + height: 200px; + position:absolute; + overflow: visible; + top: 0; + left: 0; + z-index: $mainTextInput-zindex; + .formattedTextBox-cont { + background-color: rgba(248, 6, 6, 0.001); + width: 100%; + height: 100%; + position:absolute; + top: 0; + left: 0; + } +} \ No newline at end of file diff --git a/src/client/views/MainOverlayTextBox.tsx b/src/client/views/MainOverlayTextBox.tsx new file mode 100644 index 000000000..df1addbc7 --- /dev/null +++ b/src/client/views/MainOverlayTextBox.tsx @@ -0,0 +1,110 @@ +import { action, observable, trace } from 'mobx'; +import { observer } from 'mobx-react'; +import "normalize.css"; +import * as React from 'react'; +import { Document } from '../../fields/Document'; +import { Key } from '../../fields/Key'; +import { KeyStore } from '../../fields/KeyStore'; +import { emptyDocFunction, emptyFunction, returnTrue } from '../../Utils'; +import '../northstar/model/ModelExtensions'; +import '../northstar/utils/Extensions'; +import { DragManager } from '../util/DragManager'; +import { Transform } from '../util/Transform'; +import "./MainOverlayTextBox.scss"; +import { FormattedTextBox } from './nodes/FormattedTextBox'; + +interface MainOverlayTextBoxProps { +} + +@observer +export class MainOverlayTextBox extends React.Component { + public static Instance: MainOverlayTextBox; + @observable public TextDoc?: Document = undefined; + public TextScroll: number = 0; + private _textRect: any; + private _textXf: Transform = Transform.Identity(); + private _textFieldKey: Key = KeyStore.Data; + private _textColor: string | null = null; + private _textTargetDiv: HTMLDivElement | undefined; + private _textProxyDiv: React.RefObject; + + constructor(props: MainOverlayTextBoxProps) { + super(props); + this._textProxyDiv = React.createRef(); + MainOverlayTextBox.Instance = this; + } + + @action + SetTextDoc(textDoc?: Document, textFieldKey?: Key, div?: HTMLDivElement, tx?: Transform) { + if (this._textTargetDiv) { + this._textTargetDiv.style.color = this._textColor; + } + + this.TextDoc = undefined; + this.TextDoc = textDoc; + this._textFieldKey = textFieldKey!; + this._textXf = tx ? tx : Transform.Identity(); + this._textTargetDiv = div; + if (div) { + this._textColor = div.style.color; + div.style.color = "transparent"; + this._textRect = div.getBoundingClientRect(); + this.TextScroll = div.scrollTop; + } + } + + @action + textScroll = (e: React.UIEvent) => { + if (this._textProxyDiv.current && this._textTargetDiv) { + this._textTargetDiv.scrollTop = this.TextScroll = this._textProxyDiv.current.children[0].scrollTop; + } + } + + textBoxDown = (e: React.PointerEvent) => { + if (e.button !== 0 || e.metaKey || e.altKey) { + document.addEventListener("pointermove", this.textBoxMove); + document.addEventListener('pointerup', this.textBoxUp); + } + } + textBoxMove = (e: PointerEvent) => { + if (e.movementX > 1 || e.movementY > 1) { + document.removeEventListener("pointermove", this.textBoxMove); + document.removeEventListener('pointerup', this.textBoxUp); + let dragData = new DragManager.DocumentDragData([this.TextDoc!]); + const [left, top] = this._textXf + .inverse() + .transformPoint(0, 0); + dragData.xOffset = e.clientX - left; + dragData.yOffset = e.clientY - top; + DragManager.StartDocumentDrag([this._textTargetDiv!], dragData, e.clientX, e.clientY, { + handlers: { + dragComplete: action(emptyFunction), + }, + hideSource: false + }); + } + } + textBoxUp = (e: PointerEvent) => { + document.removeEventListener("pointermove", this.textBoxMove); + document.removeEventListener('pointerup', this.textBoxUp); + } + + render() { + if (this.TextDoc) { + let x: number = this._textRect.x; + let y: number = this._textRect.y; + let w: number = this._textRect.width; + let h: number = this._textRect.height; + let t = this._textXf.transformPoint(0, 0); + let s = this._textXf.transformPoint(1, 0); + s[0] = Math.sqrt((s[0] - t[0]) * (s[0] - t[0]) + (s[1] - t[1]) * (s[1] - t[1])); + return
+
+ this._textXf} focus={emptyDocFunction} /> +
+ ; + } + else return (null); + } +} \ No newline at end of file diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 6c382a353..cb4e8fb2e 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -24,6 +24,7 @@ import "./CollectionFreeFormView.scss"; import { MarqueeView } from "./MarqueeView"; import React = require("react"); import v5 = require("uuid/v5"); +import { MainOverlayTextBox } from "../../MainOverlayTextBox"; @observer export class CollectionFreeFormView extends CollectionSubView { @@ -205,7 +206,7 @@ export class CollectionFreeFormView extends CollectionSubView { @action private SetPan(panX: number, panY: number) { - Main.Instance.SetTextDoc(); + MainOverlayTextBox.Instance.SetTextDoc(); var x1 = this.getLocalTransform().inverse().Scale; const newPanX = Math.min((1 - 1 / x1) * this.nativeWidth, Math.max(0, panX)); const newPanY = Math.min((1 - 1 / x1) * this.nativeHeight, Math.max(0, panY)); diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 2e6272836..87c1bcb1e 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -16,6 +16,7 @@ import "./FormattedTextBox.scss"; import React = require("react"); import { TextField } from "../../../fields/TextField"; import { KeyStore } from "../../../fields/KeyStore"; +import { MainOverlayTextBox } from "../MainOverlayTextBox"; const { buildMenuItems } = require("prosemirror-example-setup"); const { menuBar } = require("prosemirror-menu"); @@ -92,7 +93,7 @@ export class FormattedTextBox extends React.Component<(FieldViewProps & Formatte }; if (this.props.isOverlay) { - this._inputReactionDisposer = reaction(() => Main.Instance._textDoc && Main.Instance._textDoc.Id, + this._inputReactionDisposer = reaction(() => MainOverlayTextBox.Instance.TextDoc && MainOverlayTextBox.Instance.TextDoc.Id, () => { if (this._editorView) { this._editorView.destroy(); @@ -103,7 +104,7 @@ export class FormattedTextBox extends React.Component<(FieldViewProps & Formatte ); } else { this._proxyReactionDisposer = reaction(() => this.props.isSelected(), - () => this.props.isSelected() && Main.Instance.SetTextDoc(this.props.Document, this.props.fieldKey, this._ref.current!, this.props.ScreenToLocalTransform())); + () => this.props.isSelected() && MainOverlayTextBox.Instance.SetTextDoc(this.props.Document, this.props.fieldKey, this._ref.current!, this.props.ScreenToLocalTransform())); } this._reactionDisposer = reaction( @@ -184,10 +185,10 @@ export class FormattedTextBox extends React.Component<(FieldViewProps & Formatte onFocused = (e: React.FocusEvent): void => { if (!this.props.isOverlay) { - Main.Instance.SetTextDoc(this.props.Document, this.props.fieldKey, this._ref.current!, this.props.ScreenToLocalTransform()); + MainOverlayTextBox.Instance.SetTextDoc(this.props.Document, this.props.fieldKey, this._ref.current!, this.props.ScreenToLocalTransform()); } else { if (this._ref.current) { - this._ref.current.scrollTop = Main.Instance._textScroll; + this._ref.current.scrollTop = MainOverlayTextBox.Instance.TextScroll; } } } diff --git a/src/fields/KeyStore.ts b/src/fields/KeyStore.ts index 19431bbe3..16a909eb8 100644 --- a/src/fields/KeyStore.ts +++ b/src/fields/KeyStore.ts @@ -49,7 +49,7 @@ export namespace KeyStore { export const CopyDraggedItems = new Key("CopyDraggedItems"); export const KeyList: Key[] = [Prototype, X, Y, Page, Title, Author, PanX, PanY, Scale, NativeWidth, NativeHeight, - Width, Height, ZIndex, Data, Annotations, ViewType, Layout, BackgroundColor, BackgroundLayout, OverlayLayout, LayoutKeys, + Width, Height, ZIndex, Zoom, Data, Annotations, ViewType, Layout, BackgroundColor, BackgroundLayout, OverlayLayout, LayoutKeys, LayoutFields, ColumnsKey, SchemaSplitPercentage, Caption, ActiveWorkspace, DocumentText, BrushingDocs, LinkedToDocs, LinkedFromDocs, LinkDescription, LinkTags, Thumbnail, ThumbnailPage, CurPage, AnnotationOn, NumPages, Ink, Cursors, OptionalRightCollection, Archives, Workspaces, Minimized, CopyDraggedItems diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index 13eddafbf..34454eda0 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -1,15 +1,14 @@ -import { DashUserModel } from "./user_model"; +import { computed, observable, action } from "mobx"; import * as rp from 'request-promise'; -import { RouteStore } from "../../RouteStore"; -import { ServerUtils } from "../../ServerUtil"; +import { Documents } from "../../../client/documents/Documents"; +import { Attribute, AttributeGroup, Catalog, Schema } from "../../../client/northstar/model/idea/idea"; +import { ArrayUtil } from "../../../client/northstar/utils/ArrayUtil"; import { Server } from "../../../client/Server"; 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, Catalog } from "../../../client/northstar/model/idea/idea"; -import { observable, computed, action } from "mobx"; -import { ArrayUtil } from "../../../client/northstar/utils/ArrayUtil"; +import { RouteStore } from "../../RouteStore"; +import { ServerUtils } from "../../ServerUtil"; export class CurrentUserUtils { private static curr_email: string; @@ -17,65 +16,22 @@ export class CurrentUserUtils { private static user_document: Document; //TODO tfs: these should be temporary... private static mainDocId: string | undefined; - @observable private static catalog?: Catalog; - - public static get email(): string { - return this.curr_email; - } - - public static get id(): string { - return this.curr_id; - } - - public static get UserDocument(): Document { - return this.user_document; - } - public static get MainDocId(): string | undefined { - return this.mainDocId; - } - - public static set MainDocId(id: string | undefined) { - this.mainDocId = id; - } - - @computed public static get NorthstarDBCatalog(): Catalog | undefined { - return this.catalog; - } - public static set NorthstarDBCatalog(ctlog: Catalog | undefined) { - this.catalog = ctlog; - } - 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) => { - 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, schema.rootAttributeGroup); - return allAttributes; - } + public static get email() { return this.curr_email; } + public static get id() { return this.curr_id; } + public static get UserDocument() { return this.user_document; } + public static get MainDocId() { return this.mainDocId; } + public static set MainDocId(id: string | undefined) { this.mainDocId = id; } private static createUserDocument(id: string): Document { let doc = new Document(id); - doc.Set(KeyStore.Workspaces, new ListField()); doc.Set(KeyStore.OptionalRightCollection, Documents.SchemaDocument([], { title: "Pending documents" })); return doc; } public static loadCurrentUser(): Promise { - let userPromise = rp.get(ServerUtils.prepend(RouteStore.getCurrUser)).then((response) => { + let userPromise = rp.get(ServerUtils.prepend(RouteStore.getCurrUser)).then(response => { if (response) { let obj = JSON.parse(response); CurrentUserUtils.curr_id = obj.id as string; @@ -86,17 +42,34 @@ export class CurrentUserUtils { }); let userDocPromise = rp.get(ServerUtils.prepend(RouteStore.getUserDocumentId)).then(id => { if (id) { - return Server.GetField(id).then(field => { - if (field instanceof Document) { - this.user_document = field; - } else { - this.user_document = this.createUserDocument(id); - } - }); + return Server.GetField(id).then(field => + this.user_document = field instanceof Document ? field : this.createUserDocument(id)); } else { throw new Error("There should be a user id! Why does Dash think there isn't one?"); } }); return Promise.all([userPromise, userDocPromise]); } + + /* Northstar catalog ... really just for testing so this should eventually go away */ + @observable private static _northstarCatalog?: Catalog; + @computed public static get NorthstarDBCatalog() { return this._northstarCatalog; } + public static set NorthstarDBCatalog(ctlog: Catalog | undefined) { this._northstarCatalog = ctlog; } + + public static GetNorthstarSchema(name: string): Schema | undefined { + return !this._northstarCatalog || !this._northstarCatalog.schemas ? undefined : + ArrayUtil.FirstOrDefault(this._northstarCatalog.schemas, (s: Schema) => s.displayName === name); + } + public static GetAllNorthstarColumnAttributes(schema: Schema) { + const recurs = (attrs: Attribute[], g?: AttributeGroup) => { + if (g && g.attributes) { + attrs.push.apply(attrs, g.attributes); + if (g.attributeGroups) { + g.attributeGroups.forEach(ng => recurs(attrs, ng)); + } + } + return attrs; + }; + return recurs([] as Attribute[], schema ? schema.rootAttributeGroup : undefined); + } } \ No newline at end of file diff --git a/src/server/authentication/models/user_model.ts b/src/server/authentication/models/user_model.ts index 1c6926517..d5c84c311 100644 --- a/src/server/authentication/models/user_model.ts +++ b/src/server/authentication/models/user_model.ts @@ -18,8 +18,8 @@ mongoose.connection.on('disconnected', function () { export type DashUserModel = mongoose.Document & { email: string, password: string, - passwordResetToken: string | undefined, - passwordResetExpires: Date | undefined, + passwordResetToken?: string, + passwordResetExpires?: Date, userDocumentId: string; @@ -67,11 +67,17 @@ const userSchema = new mongoose.Schema({ */ userSchema.pre("save", function save(next) { const user = this as DashUserModel; - if (!user.isModified("password")) { return next(); } + if (!user.isModified("password")) { + return next(); + } bcrypt.genSalt(10, (err, salt) => { - if (err) { return next(err); } + if (err) { + return next(err); + } bcrypt.hash(user.password, salt, () => void {}, (err: mongoose.Error, hash) => { - if (err) { return next(err); } + if (err) { + return next(err); + } user.password = hash; next(); }); @@ -79,9 +85,8 @@ userSchema.pre("save", function save(next) { }); const comparePassword: comparePasswordFunction = function (this: DashUserModel, candidatePassword, cb) { - bcrypt.compare(candidatePassword, this.password, (err: mongoose.Error, isMatch: boolean) => { - cb(err, isMatch); - }); + bcrypt.compare(candidatePassword, this.password, (err: mongoose.Error, isMatch: boolean) => + cb(err, isMatch)); }; userSchema.methods.comparePassword = comparePassword; -- cgit v1.2.3-70-g09d2 From 6c0b421db6aa3204bbc6e42139d240f503000b5d Mon Sep 17 00:00:00 2001 From: bob Date: Mon, 15 Apr 2019 11:59:50 -0400 Subject: fixed zoom fading somewhat. --- src/Utils.ts | 15 ++++++++++ src/client/northstar/dash-fields/HistogramField.ts | 12 ++------ src/client/views/Main.tsx | 3 +- src/client/views/MainOverlayTextBox.tsx | 3 +- .../views/collections/CollectionDockingView.tsx | 3 +- .../views/collections/CollectionSchemaView.tsx | 3 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 19 ++++++------- .../views/nodes/CollectionFreeFormDocumentView.tsx | 18 ++++++++---- src/client/views/nodes/DocumentContentsView.tsx | 33 ++-------------------- src/client/views/nodes/DocumentView.tsx | 1 - src/client/views/nodes/FieldView.tsx | 3 +- src/client/views/nodes/FormattedTextBox.tsx | 4 ++- 12 files changed, 51 insertions(+), 66 deletions(-) (limited to 'src/client/northstar') diff --git a/src/Utils.ts b/src/Utils.ts index e07d4e82d..dec6245ef 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -87,10 +87,25 @@ export class Utils { } } +export function OmitKeys(obj: any, keys: any, addKeyFunc?: (dup: any) => void) { + var dup: any = {}; + for (var key in obj) { + if (keys.indexOf(key) === -1) { + dup[key] = obj[key]; + } + } + addKeyFunc && addKeyFunc(dup); + return dup; +} + export function returnTrue() { return true; } export function returnFalse() { return false; } +export function returnOne() { return 1; } + +export function returnZero() { return 0; } + export function emptyFunction() { } export function emptyDocFunction(doc: Document) { } diff --git a/src/client/northstar/dash-fields/HistogramField.ts b/src/client/northstar/dash-fields/HistogramField.ts index 82de51d56..c699691a4 100644 --- a/src/client/northstar/dash-fields/HistogramField.ts +++ b/src/client/northstar/dash-fields/HistogramField.ts @@ -6,6 +6,7 @@ import { BasicField } from "../../../fields/BasicField"; import { Field, FieldId } from "../../../fields/Field"; import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils"; import { Types } from "../../../server/Message"; +import { OmitKeys } from "../../../Utils"; export class HistogramField extends BasicField { @@ -13,17 +14,8 @@ 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 { - return JSON.stringify(this.omitKeys(this.Data, ['Links', 'BrushLinks', 'Result', 'BrushColors', 'FilterModels', 'FilterOperand'])); + return JSON.stringify(OmitKeys(this.Data, ['Links', 'BrushLinks', 'Result', 'BrushColors', 'FilterModels', 'FilterOperand'])); } Copy(): Field { diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index d26586216..98ef329c7 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -17,7 +17,7 @@ import { CurrentUserUtils } from '../../server/authentication/models/current_use import { MessageStore } from '../../server/Message'; import { RouteStore } from '../../server/RouteStore'; import { ServerUtils } from '../../server/ServerUtil'; -import { emptyDocFunction, emptyFunction, returnTrue, Utils } from '../../Utils'; +import { emptyDocFunction, emptyFunction, returnTrue, Utils, returnOne } from '../../Utils'; import { Documents } from '../documents/Documents'; import { ColumnAttributeModel } from '../northstar/core/attribute/AttributeModel'; import { AttributeTransformationModel } from '../northstar/core/attribute/AttributeTransformationModel'; @@ -178,7 +178,6 @@ export class Main extends React.Component { @action textScroll = (e: React.UIEvent) => { if (this._textProxyDiv.current && this._textTargetDiv) { - this._textTargetDiv.scrollTop = this.TextScroll = this._textProxyDiv.current.children[0].scrollTop; + this.TextScroll = (e as any)._targetInst.stateNode.scrollTop;// this._textProxyDiv.current.children[0].scrollTop; + this._textTargetDiv.scrollTop = this.TextScroll; } } diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 4f7d4fc0d..2b96e7678 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -8,7 +8,7 @@ import { Document } from "../../../fields/Document"; import { KeyStore } from "../../../fields/KeyStore"; import Measure from "react-measure"; import { FieldId, Opt, Field, FieldWaiting } from "../../../fields/Field"; -import { Utils, returnTrue, emptyFunction, emptyDocFunction } from "../../../Utils"; +import { Utils, returnTrue, emptyFunction, emptyDocFunction, returnOne } from "../../../Utils"; import { Server } from "../../Server"; import { undoBatch } from "../../util/UndoManager"; import { DocumentView } from "../nodes/DocumentView"; @@ -343,7 +343,6 @@ export class DockedFrameRenderer extends React.Component { ); + let zoomFade = !this.isAnnotationOverlay || (dv && SelectionManager.IsSelected(dv)) ? 1 : + Math.max(0, 2 - (zoom < this.scale ? this.scale / zoom : zoom / this.scale)); + if (page === curPage || page === -1) { + prev.push(); } return prev; }, [] as JSX.Element[]); @@ -305,13 +304,13 @@ export class CollectionFreeFormView extends CollectionSubView { @computed get backgroundView() { return !this.backgroundLayout ? (null) : - (); } @computed get overlayView() { return !this.overlayLayout ? (null) : - (); } diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 0aa152209..b00cefbf6 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -1,4 +1,4 @@ -import { computed } from "mobx"; +import { computed, trace } from "mobx"; import { observer } from "mobx-react"; import { KeyStore } from "../../../fields/KeyStore"; import { NumberField } from "../../../fields/NumberField"; @@ -6,13 +6,17 @@ import { Transform } from "../../util/Transform"; import { DocumentView, DocumentViewProps } from "./DocumentView"; import "./DocumentView.scss"; import React = require("react"); +import { OmitKeys } from "../../../Utils"; +export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps { + zoomFade: number; +} @observer -export class CollectionFreeFormDocumentView extends React.Component { +export class CollectionFreeFormDocumentView extends React.Component { private _mainCont = React.createRef(); - constructor(props: DocumentViewProps) { + constructor(props: CollectionFreeFormDocumentViewProps) { super(props); } @@ -55,20 +59,24 @@ export class CollectionFreeFormDocumentView extends React.Component; } + @computed + get docViewProps(): DocumentViewProps { + return (OmitKeys(this.props, ['zoomFade'])); + } panelWidth = () => this.props.Document.GetBoolean(KeyStore.Minimized, false) ? 10 : this.props.PanelWidth(); panelHeight = () => this.props.Document.GetBoolean(KeyStore.Minimized, false) ? 10 : this.props.PanelHeight(); render() { return (
; @@ -44,35 +44,8 @@ export class DocumentContentsView extends React.Component obj.active = this.props.parentActive) }; + for (const key of this.layoutKeys) { bindings[key.Name + "Key"] = key; // this maps string values of the form Key to an actual key Kestore.keyname e.g, "DataKey" => KeyStore.Data } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 935540af1..bcd746024 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -28,7 +28,6 @@ import React = require("react"); export interface DocumentViewProps { ContainingCollectionView: Opt; Document: Document; - opacity: number; addDocument?: (doc: Document, allowDuplicates?: boolean) => boolean; removeDocument?: (doc: Document) => boolean; moveDocument?: (doc: Document, targetCollection: Document, addDocument: (document: Document) => boolean) => boolean; diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index 562de4827..ebd25f937 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -19,7 +19,7 @@ import { ListField } from "../../../fields/ListField"; import { DocumentContentsView } from "./DocumentContentsView"; import { Transform } from "../../util/Transform"; import { KeyStore } from "../../../fields/KeyStore"; -import { returnFalse, emptyDocFunction } from "../../../Utils"; +import { returnFalse, emptyDocFunction, emptyFunction, returnOne } from "../../../Utils"; import { CollectionView } from "../collections/CollectionView"; import { CollectionPDFView } from "../collections/CollectionPDFView"; import { CollectionVideoView } from "../collections/CollectionVideoView"; @@ -83,7 +83,6 @@ export class FieldView extends React.Component { 1} PanelWidth={() => 100} diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 87c1bcb1e..ad1ed5df0 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -1,4 +1,4 @@ -import { action, IReactionDisposer, reaction } from "mobx"; +import { action, IReactionDisposer, reaction, trace, computed } from "mobx"; import { baseKeymap } from "prosemirror-commands"; import { history, redo, undo } from "prosemirror-history"; import { keymap } from "prosemirror-keymap"; @@ -17,6 +17,7 @@ import React = require("react"); import { TextField } from "../../../fields/TextField"; import { KeyStore } from "../../../fields/KeyStore"; import { MainOverlayTextBox } from "../MainOverlayTextBox"; +import { observer } from "mobx-react"; const { buildMenuItems } = require("prosemirror-example-setup"); const { menuBar } = require("prosemirror-menu"); @@ -41,6 +42,7 @@ export interface FormattedTextBoxOverlay { isOverlay?: boolean; } +@observer export class FormattedTextBox extends React.Component<(FieldViewProps & FormattedTextBoxOverlay)> { public static LayoutString(fieldStr: string = "DataKey") { return FieldView.LayoutString(FormattedTextBox, fieldStr); -- cgit v1.2.3-70-g09d2 From 21b1e20106ff49c02657c88f503ef46bc7e4fb07 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Tue, 16 Apr 2019 23:09:03 -0400 Subject: various bug fixes --- src/client/northstar/dash-nodes/HistogramBox.tsx | 2 +- .../views/collections/CollectionBaseView.tsx | 9 ++++-- .../views/collections/CollectionDockingView.scss | 5 ++++ .../views/collections/CollectionDockingView.tsx | 7 ++++- .../views/collections/CollectionSchemaView.tsx | 14 ++++++---- src/client/views/collections/CollectionView.tsx | 4 ++- .../CollectionFreeFormLinksView.tsx | 4 +-- .../CollectionFreeFormRemoteCursors.tsx | 2 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 2 +- .../collections/collectionFreeForm/MarqueeView.tsx | 1 - src/client/views/nodes/DocumentView.scss | 4 +-- src/client/views/nodes/ImageBox.tsx | 32 ++++++---------------- 12 files changed, 44 insertions(+), 42 deletions(-) (limited to 'src/client/northstar') diff --git a/src/client/northstar/dash-nodes/HistogramBox.tsx b/src/client/northstar/dash-nodes/HistogramBox.tsx index 3e94fed81..0e84ace50 100644 --- a/src/client/northstar/dash-nodes/HistogramBox.tsx +++ b/src/client/northstar/dash-nodes/HistogramBox.tsx @@ -118,7 +118,7 @@ export class HistogramBox extends React.Component { this.props.Document.GetTAsync(this.props.fieldKey, HistogramField).then((histoOp: Opt) => runInAction(() => { this.HistoOp = histoOp ? histoOp.Data : HistogramOperation.Empty; if (this.HistoOp !== HistogramOperation.Empty) { - reaction(() => this.props.Document.GetList(KeyStore.LinkedFromDocs, []), (docs: Document[]) => this.HistoOp.Links.splice(0, this.HistoOp.Links.length, ...docs), { fireImmediately: true }); + reaction(() => this.props.Document.GetList(KeyStore.LinkedFromDocs, [] as Document[]), (docs) => this.HistoOp.Links.splice(0, this.HistoOp.Links.length, ...docs), { fireImmediately: true }); reaction(() => this.props.Document.GetList(KeyStore.BrushingDocs, []).length, () => { let brushingDocs = this.props.Document.GetList(KeyStore.BrushingDocs, [] as Document[]); diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx index 444f6fc26..4fda38a26 100644 --- a/src/client/views/collections/CollectionBaseView.tsx +++ b/src/client/views/collections/CollectionBaseView.tsx @@ -61,13 +61,16 @@ export class CollectionBaseView extends React.Component { } createsCycle(documentToAdd: Document, containerDocument: Document): boolean { - let data = documentToAdd.GetList(KeyStore.Data, []); - for (const doc of data) { + if (!(documentToAdd instanceof Document)) { + return false; + } + let data = documentToAdd.GetList(KeyStore.Data, [] as Document[]); + for (const doc of data.filter(d => d instanceof Document)) { if (this.createsCycle(doc, containerDocument)) { return true; } } - let annots = documentToAdd.GetList(KeyStore.Annotations, []); + let annots = documentToAdd.GetList(KeyStore.Annotations, [] as Document[]); for (const annot of annots) { if (this.createsCycle(annot, containerDocument)) { return true; diff --git a/src/client/views/collections/CollectionDockingView.scss b/src/client/views/collections/CollectionDockingView.scss index 0e7e0afa7..5ed4567cf 100644 --- a/src/client/views/collections/CollectionDockingView.scss +++ b/src/client/views/collections/CollectionDockingView.scss @@ -2,6 +2,11 @@ .collectiondockingview-content { height: 100%; + text-align:center; + .documentView-node-topmost { + transform-origin: center top; + display: inline-block; + } } .lm_active .messageCounter{ color:white; diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 4ea21b2f5..b998362f4 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -327,7 +327,12 @@ export class DockedFrameRenderer extends React.Component { private _nativeWidth = () => this._document!.GetNumber(KeyStore.NativeWidth, this._panelWidth); private _nativeHeight = () => this._document!.GetNumber(KeyStore.NativeHeight, this._panelHeight); - private _contentScaling = () => this._panelWidth / (this._nativeWidth() ? this._nativeWidth() : this._panelWidth); + private _contentScaling = () => { + let wscale = this._panelWidth / (this._nativeWidth() ? this._nativeWidth() : this._panelWidth); + if (wscale * this._nativeHeight() > this._panelHeight) + return this._panelHeight / (this._nativeHeight() ? this._nativeHeight() : this._panelHeight); + return wscale; + } ScreenToLocalTransform = () => { let { scale, translateX, translateY } = Utils.GetScreenTransform(this._mainCont.current!); diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index 4f4068e7a..1defdba7e 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -167,7 +167,7 @@ export class CollectionSchemaView extends CollectionSubView { @computed get columns() { - return this.props.Document.GetList(KeyStore.ColumnsKey, []); + return this.props.Document.GetList(KeyStore.ColumnsKey, [] as Key[]); } @action @@ -195,7 +195,7 @@ export class CollectionSchemaView extends CollectionSubView { @computed get findAllDocumentKeys(): { [id: string]: boolean } { - const docs = this.props.Document.GetList(this.props.fieldKey, []); + const docs = this.props.Document.GetList(this.props.fieldKey, [] as Document[]); let keys: { [id: string]: boolean } = {}; if (this._optionsActivated > -1) { // bcz: ugh. this is untracked since otherwise a large collection of documents will blast the server for all their fields. @@ -237,7 +237,7 @@ export class CollectionSchemaView extends CollectionSubView { } @action setScaling = (r: any) => { - const children = this.props.Document.GetList(this.props.fieldKey, []); + const children = this.props.Document.GetList(this.props.fieldKey, [] as Document[]); const selected = children.length > this._selectedIndex ? children[this._selectedIndex] : undefined; this._panelWidth = r.entry.width; this._panelHeight = r.entry.height ? r.entry.height : this._panelHeight; @@ -253,8 +253,10 @@ export class CollectionSchemaView extends CollectionSubView { getPreviewTransform = (): Transform => this.props.ScreenToLocalTransform().translate(- this.borderWidth - this.DIVIDER_WIDTH - this._dividerX - this._tableWidth, - this.borderWidth).scale(1 / this._contentScaling); onPointerDown = (e: React.PointerEvent): void => { - if (e.button === 1 && this.props.isSelected() && !e.altKey && !e.ctrlKey && !e.metaKey) { - e.stopPropagation(); + if (e.button === 0 && !e.altKey && !e.ctrlKey && !e.metaKey) { + if (this.props.isSelected()) + e.stopPropagation(); + else e.preventDefault(); } } @@ -293,7 +295,7 @@ export class CollectionSchemaView extends CollectionSubView { library.add(faCog); library.add(faPlus); const columns = this.columns; - const children = this.props.Document.GetList(this.props.fieldKey, []); + const children = this.props.Document.GetList(this.props.fieldKey, [] as Document[]); const selected = children.length > this._selectedIndex ? children[this._selectedIndex] : undefined; //all the keys/columns that will be displayed in the schema const allKeys = this.findAllDocumentKeys; diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index bd7a5635f..675e720e2 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -29,8 +29,10 @@ export class CollectionView extends React.Component { return (null); } + get isAnnotationOverlay() { return this.props.fieldKey && this.props.fieldKey.Id === KeyStore.Annotations.Id; } // bcz: ? Why do we need to compare Id's? + onContextMenu = (e: React.MouseEvent): void => { - if (!e.isPropagationStopped() && this.props.Document.Id !== CurrentUserUtils.MainDocId) { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 + if (!this.isAnnotationOverlay && !e.isPropagationStopped() && this.props.Document.Id !== CurrentUserUtils.MainDocId) { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 ContextMenu.Instance.addItem({ description: "Freeform", event: undoBatch(() => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Freeform)) }); ContextMenu.Instance.addItem({ description: "Schema", event: undoBatch(() => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Schema)) }); ContextMenu.Instance.addItem({ description: "Treeview", event: undoBatch(() => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Tree)) }); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx index 2f684a54e..cd74d3a84 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx @@ -16,9 +16,9 @@ export class CollectionFreeFormLinksView extends React.Component this.props.Document.GetList(this.props.fieldKey, []).map(doc => doc.GetNumber(KeyStore.X, 0)), + this._brushReactionDisposer = reaction(() => this.props.Document.GetList(this.props.fieldKey, [] as Document[]).map(doc => doc.GetNumber(KeyStore.X, 0)), () => { - let views = this.props.Document.GetList(this.props.fieldKey, []); + let views = this.props.Document.GetList(this.props.fieldKey, [] as Document[]); for (let i = 0; i < views.length; i++) { for (let j = 0; j < views.length; j++) { let srcDoc = views[j]; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx index 751ea8190..cf0a6de00 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx @@ -12,7 +12,7 @@ export class CollectionFreeFormRemoteCursors extends React.Component(KeyStore.Cursors, []); + let cursors = doc.GetList(KeyStore.Cursors, [] as CursorEntry[]); let notMe = cursors.filter(entry => entry.Data[0][0] !== id); return id ? notMe : []; } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 3ae64d2c6..97708ce19 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -218,7 +218,7 @@ export class CollectionFreeFormView extends CollectionSubView { @action bringToFront(doc: Document) { - this.props.Document.GetList(this.props.fieldKey, []).slice().sort((doc1, doc2) => { + this.props.Document.GetList(this.props.fieldKey, [] as Document[]).slice().sort((doc1, doc2) => { if (doc1 === doc) return 1; if (doc2 === doc) return -1; return doc1.GetNumber(KeyStore.ZIndex, 0) - doc2.GetNumber(KeyStore.ZIndex, 0); diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 96d59c831..65f461b27 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -147,7 +147,6 @@ export class MarqueeView extends React.Component d.SetNumber(KeyStore.X, d.GetNumber(KeyStore.X, 0) - bounds.left - bounds.width / 2); d.SetNumber(KeyStore.Y, d.GetNumber(KeyStore.Y, 0) - bounds.top - bounds.height / 2); d.SetNumber(KeyStore.Page, -1); - d.SetText(KeyStore.Title, "" + d.Width() + " " + d.Height()); return d; }); let ink = this.props.container.props.Document.GetT(KeyStore.Ink, InkField); diff --git a/src/client/views/nodes/DocumentView.scss b/src/client/views/nodes/DocumentView.scss index 6383ac3f6..690ee50e8 100644 --- a/src/client/views/nodes/DocumentView.scss +++ b/src/client/views/nodes/DocumentView.scss @@ -1,6 +1,6 @@ @import "../globalCssVariables"; -.documentView-node, .documentView-node-topMost { +.documentView-node, .documentView-node-topmost { position: inherit; top: 0; left:0; @@ -29,7 +29,7 @@ height: calc(100% - 20px); } } -.documentView-node-topMost { +.documentView-node-topmost { background: white; } diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index ac54321d5..fe0b07bc0 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -1,24 +1,20 @@ -import { action, observable, trace } from 'mobx'; +import { action, observable } from 'mobx'; import { observer } from "mobx-react"; import Lightbox from 'react-image-lightbox'; import 'react-image-lightbox/style.css'; // This only needs to be imported once in your app +import { Document } from '../../../fields/Document'; import { FieldWaiting } from '../../../fields/Field'; import { ImageField } from '../../../fields/ImageField'; import { KeyStore } from '../../../fields/KeyStore'; +import { ListField } from '../../../fields/ListField'; +import { Utils } from '../../../Utils'; +import { DragManager } from '../../util/DragManager'; +import { undoBatch } from '../../util/UndoManager'; import { ContextMenu } from "../../views/ContextMenu"; import { FieldView, FieldViewProps } from './FieldView'; import "./ImageBox.scss"; import React = require("react"); -import { Utils } from '../../../Utils'; -import { ListField } from '../../../fields/ListField'; -import { DragManager } from '../../util/DragManager'; -import { undoBatch, UndoManager } from '../../util/UndoManager'; -import { TextField } from '../../../fields/TextField'; -import { Document } from '../../../fields/Document'; -import { RouteStore } from '../../../server/RouteStore'; -import { ServerUtils } from '../../../server/ServerUtil'; -import { CollectionSubView } from '../collections/CollectionSubView'; @observer export class ImageBox extends React.Component { @@ -36,10 +32,6 @@ export class ImageBox extends React.Component { super(props); this._imgRef = React.createRef(); - this.state = { - photoIndex: 0, - isOpen: false, - }; } @action @@ -49,8 +41,6 @@ export class ImageBox extends React.Component { if (this._photoIndex == 0) this.props.Document.SetNumber(KeyStore.NativeHeight, this.props.Document.GetNumber(KeyStore.NativeWidth, 0) * h / w); } - componentDidMount() { - } protected createDropTarget = (ele: HTMLDivElement) => { if (this.dropDisposer) { @@ -60,10 +50,6 @@ export class ImageBox extends React.Component { this.dropDisposer = DragManager.MakeDropTarget(ele, { handlers: { drop: this.drop.bind(this) } }); } } - - componentWillUnmount() { - } - onDrop = (e: React.DragEvent) => { e.stopPropagation(); e.preventDefault(); @@ -158,8 +144,8 @@ export class ImageBox extends React.Component { let dist = Math.min(nativeWidth / paths.length, 40); let left = (nativeWidth - paths.length * dist) / 2; return paths.map((p, i) => -
-
{ e.stopPropagation(); this.onDotDown(i); }} /> +
+
{ e.stopPropagation(); this.onDotDown(i); }} />
) } @@ -174,7 +160,7 @@ export class ImageBox extends React.Component { return (
Image not found - {this.dots(paths)} + {paths.length > 1 ? this.dots(paths) : (null)} {this.lightbox(paths)}
); } -- cgit v1.2.3-70-g09d2 From af6feb64510490da8d815f41ceb639d693b9eae3 Mon Sep 17 00:00:00 2001 From: bob Date: Fri, 19 Apr 2019 16:34:32 -0400 Subject: played with iconifying things in a different way. fixed some things with schemas. --- src/Utils.ts | 2 +- src/client/documents/Documents.ts | 16 ++++ src/client/northstar/dash-nodes/HistogramBox.scss | 6 +- src/client/northstar/dash-nodes/HistogramBox.tsx | 2 +- src/client/views/DocumentDecorations.tsx | 42 ++++++---- src/client/views/Main.tsx | 8 +- .../views/collections/CollectionSchemaView.scss | 9 ++- .../views/collections/CollectionSchemaView.tsx | 5 +- .../CollectionFreeFormLinkView.tsx | 8 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 13 ++-- .../collections/collectionFreeForm/MarqueeView.tsx | 9 +-- src/client/views/globalCssVariables.scss | 2 + src/client/views/globalCssVariables.scss.d.ts | 1 + .../views/nodes/CollectionFreeFormDocumentView.tsx | 26 +++---- src/client/views/nodes/DocumentContentsView.tsx | 3 +- src/client/views/nodes/DocumentView.scss | 16 +--- src/client/views/nodes/DocumentView.tsx | 71 ++++++++--------- src/client/views/nodes/FieldView.tsx | 5 ++ src/client/views/nodes/IconBox.scss | 12 +++ src/client/views/nodes/IconBox.tsx | 90 ++++++++++++++++++++++ src/fields/IconFIeld.ts | 25 ++++++ src/fields/KeyStore.ts | 10 +-- src/server/Message.ts | 2 +- src/server/ServerUtil.ts | 2 + 24 files changed, 264 insertions(+), 121 deletions(-) create mode 100644 src/client/views/nodes/IconBox.scss create mode 100644 src/client/views/nodes/IconBox.tsx create mode 100644 src/fields/IconFIeld.ts (limited to 'src/client/northstar') diff --git a/src/Utils.ts b/src/Utils.ts index dec6245ef..98f75d3b9 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -1,7 +1,7 @@ import v4 = require('uuid/v4'); import v5 = require("uuid/v5"); import { Socket } from 'socket.io'; -import { Message, Types, Transferable } from './server/Message'; +import { Message } from './server/Message'; import { Document } from './fields/Document'; export class Utils { diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 4febfa7eb..b0bb74d89 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -32,6 +32,9 @@ import { action } from "mobx"; import { ColumnAttributeModel } from "../northstar/core/attribute/AttributeModel"; import { AttributeTransformationModel } from "../northstar/core/attribute/AttributeTransformationModel"; import { AggregateFunction } from "../northstar/model/idea/idea"; +import { MINIMIZED_ICON_SIZE } from "../views/globalCssVariables.scss"; +import { IconBox } from "../views/nodes/IconBox"; +import { IconField } from "../../fields/IconFIeld"; export interface DocumentOptions { x?: number; @@ -63,6 +66,7 @@ export namespace Documents { let videoProto: Document; let audioProto: Document; let pdfProto: Document; + let iconProto: Document; const textProtoId = "textProto"; const histoProtoId = "histoProto"; const pdfProtoId = "pdfProto"; @@ -72,6 +76,7 @@ export namespace Documents { const kvpProtoId = "kvpProto"; const videoProtoId = "videoProto"; const audioProtoId = "audioProto"; + const iconProtoId = "iconProto"; export function initProtos(): Promise { return Server.GetFields([textProtoId, histoProtoId, collProtoId, pdfProtoId, imageProtoId, videoProtoId, audioProtoId, webProtoId, kvpProtoId]).then(fields => { @@ -84,6 +89,7 @@ export namespace Documents { videoProto = fields[videoProtoId] as Document || CreateVideoPrototype(); audioProto = fields[audioProtoId] as Document || CreateAudioPrototype(); pdfProto = fields[pdfProtoId] as Document || CreatePdfPrototype(); + iconProto = fields[iconProtoId] as Document || CreateIconPrototype(); }); } function assignOptions(doc: Document, options: DocumentOptions): Document { @@ -92,6 +98,8 @@ export namespace Documents { if (options.title !== undefined) { doc.SetText(KeyStore.Title, options.title); } if (options.page !== undefined) { doc.SetNumber(KeyStore.Page, options.page); } if (options.scale !== undefined) { doc.SetNumber(KeyStore.Scale, options.scale); } + if (options.width !== undefined) { doc.SetNumber(KeyStore.Width, options.width); } + if (options.height !== undefined) { doc.SetNumber(KeyStore.Height, options.height); } if (options.viewType !== undefined) { doc.SetNumber(KeyStore.ViewType, options.viewType); } if (options.backgroundColor !== undefined) { doc.SetText(KeyStore.BackgroundColor, options.backgroundColor); } if (options.ink !== undefined) { doc.Set(KeyStore.Ink, new InkField(options.ink)); } @@ -139,6 +147,11 @@ export namespace Documents { histoProto.SetText(KeyStore.BackgroundLayout, HistogramBox.LayoutString()); return histoProto; } + function CreateIconPrototype(): Document { + let iconProto = setupPrototypeOptions(iconProtoId, "ICON_PROTO", IconBox.LayoutString(), + { x: 0, y: 0, width: Number(MINIMIZED_ICON_SIZE), height: Number(MINIMIZED_ICON_SIZE), layoutKeys: [KeyStore.Data] }); + return iconProto; + } function CreateTextPrototype(): Document { let textProto = setupPrototypeOptions(textProtoId, "TEXT_PROTO", FormattedTextBox.LayoutString(), { x: 0, y: 0, width: 300, height: 150, layoutKeys: [KeyStore.Data] }); @@ -203,6 +216,9 @@ export namespace Documents { export function TextDocument(options: DocumentOptions = {}) { return assignToDelegate(SetInstanceOptions(textProto, options, ["", TextField]).MakeDelegate(), options); } + export function IconDocument(icon: string, options: DocumentOptions = {}) { + return assignToDelegate(SetInstanceOptions(iconProto, { width: Number(MINIMIZED_ICON_SIZE), height: Number(MINIMIZED_ICON_SIZE), layoutKeys: [KeyStore.Data], layout: IconBox.LayoutString(), ...options }, [icon, IconField]), options); + } export function PdfDocument(url: string, options: DocumentOptions = {}) { return assignToDelegate(SetInstanceOptions(pdfProto, options, [new URL(url), PDFField]).MakeDelegate(), options); } diff --git a/src/client/northstar/dash-nodes/HistogramBox.scss b/src/client/northstar/dash-nodes/HistogramBox.scss index e899cf15e..06d781263 100644 --- a/src/client/northstar/dash-nodes/HistogramBox.scss +++ b/src/client/northstar/dash-nodes/HistogramBox.scss @@ -1,12 +1,12 @@ .histogrambox-container { padding: 0vw; position: absolute; - top: 0; - left:0; + top: -50%; + left:-50%; text-align: center; width: 100%; height: 100%; - background: black; + background: black; } .histogrambox-xaxislabel { position:absolute; diff --git a/src/client/northstar/dash-nodes/HistogramBox.tsx b/src/client/northstar/dash-nodes/HistogramBox.tsx index 0e84ace50..e2ecc8c83 100644 --- a/src/client/northstar/dash-nodes/HistogramBox.tsx +++ b/src/client/northstar/dash-nodes/HistogramBox.tsx @@ -146,7 +146,7 @@ export class HistogramBox extends React.Component { return ( runInAction(() => { this.PanelWidth = r.entry.width; this.PanelHeight = r.entry.height; })}> {({ measureRef }) => -
+
{labelY} diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index cfb9befd5..da2c7a3be 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -5,17 +5,18 @@ import { KeyStore } from "../../fields/KeyStore"; import { ListField } from "../../fields/ListField"; import { NumberField } from "../../fields/NumberField"; import { TextField } from "../../fields/TextField"; +import { Document } from "../../fields/Document"; import { emptyFunction } from "../../Utils"; import { DragLinksAsDocuments, DragManager } from "../util/DragManager"; import { SelectionManager } from "../util/SelectionManager"; import { undoBatch } from "../util/UndoManager"; import './DocumentDecorations.scss'; import { MainOverlayTextBox } from "./MainOverlayTextBox"; -import { MINIMIZED_ICON_SIZE } from "../views/globalCssVariables.scss"; import { DocumentView } from "./nodes/DocumentView"; import { LinkMenu } from "./nodes/LinkMenu"; import React = require("react"); import { CompileScript } from "../util/Scripting"; +import { IconBox } from "./nodes/IconBox"; const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; @@ -191,6 +192,9 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> document.addEventListener("pointerup", this.onMinimizeUp); } } + + @observable _minimizedX = 0; + @observable _minimizedY = 0; @action onMinimizeMove = (e: PointerEvent): void => { e.stopPropagation(); @@ -201,12 +205,20 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> let xf = SelectionManager.SelectedDocuments()[0].props.ScreenToLocalTransform().inverse().transformPoint(0, 0); let dx = e.pageX - xf[0]; let dy = e.pageY - xf[1]; - if (Math.abs(dx) < 20 && Math.abs(dy) < 20) - dx = dy = 0; + this._minimizedX = e.clientX; + this._minimizedY = e.clientY; + if (Math.abs(dx) < 20 && Math.abs(dy) < 20) { + this._minimizedX = xf[0]; + this._minimizedY = xf[1]; + } SelectionManager.SelectedDocuments().map(dv => { - let where = (dv.props.ScreenToLocalTransform()).scale(dv.props.ContentScaling()).transformDirection(dx, dy); - dv.props.Document.SetNumber(KeyStore.MinimizedX, where[0]); - dv.props.Document.SetNumber(KeyStore.MinimizedY, where[1]); + let minDoc = dv.props.Document.Get(KeyStore.MinimizedDoc); + if (minDoc instanceof Document) { + let where = (dv.props.ScreenToLocalTransform()).scale(dv.props.ContentScaling()).transformPoint(this._minimizedX, this._minimizedY); + let minDocument = minDoc as Document; + minDocument.SetNumber(KeyStore.X, where[0] + dv.props.Document.GetNumber(KeyStore.X, 0)); + minDocument.SetNumber(KeyStore.Y, where[1] + dv.props.Document.GetNumber(KeyStore.Y, 0)); + } }); } } @@ -219,6 +231,8 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> if (Math.abs(dx) < 4 && Math.abs(dy) < 4 && !this._iconifying) { SelectionManager.SelectedDocuments().map(dv => dv.minimize()); SelectionManager.DeselectAll(); + } else { + this._minimizedX = this._minimizedY = 0; } document.removeEventListener("pointermove", this.onMinimizeMove); document.removeEventListener("pointerup", this.onMinimizeUp); @@ -404,24 +418,18 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> if (bounds.x === Number.MAX_VALUE || !seldoc) { return (null); } - let minvec = [seldoc.props.Document.GetNumber(KeyStore.MinimizedX, 0), seldoc.props.Document.GetNumber(KeyStore.MinimizedY, 0)]; - minvec = seldoc.props.ScreenToLocalTransform().scale(seldoc.props.ContentScaling()).inverse().transformDirection(minvec[0], minvec[1]); - let selpos = minvec[0] !== 0 || minvec[1] !== 0 ? - [minvec[0] - 12 + (!this._iconifying ? 8 : 0), minvec[1] - 12 + (!this._iconifying ? 28 : 0)] : + let selpos = this._minimizedX !== 0 || this._minimizedY !== 0 ? + [this._minimizedX - 12 + (!this._iconifying ? 8 : 0), this._minimizedY - 12 + (!this._iconifying ? 28 : 0)] : [0, this._iconifying ? -18 : 0]; let minimizeIcon = (
- {SelectionManager.SelectedDocuments().length == 1 ? SelectionManager.SelectedDocuments()[0].minimizedIcon : "..."} + {SelectionManager.SelectedDocuments().length == 1 ? IconBox.DocumentIcon(SelectionManager.SelectedDocuments()[0].props.Document.GetText(KeyStore.Layout, "...")) : "..."}
); if (this._iconifying) { - let xfpt = seldoc.props.ScreenToLocalTransform().inverse().transformPoint(0, 0); - return (
- {minimizeIcon} -
); + return (
{minimizeIcon}
); } - // console.log(this._documents.length) - // let test = this._documents[0].props.Document.Title; + if (this.Hidden) { return (null); } diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index 503a11b35..09ef30f6b 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -85,11 +85,11 @@ export class Main extends React.Component { this.initEventListeners(); this.initAuthenticationRouters(); - // try { - // this.initializeNorthstar(); - // } catch (e) { + try { + this.initializeNorthstar(); + } catch (e) { - // } + } } componentDidMount() { window.onpopstate = this.onHistory; } diff --git a/src/client/views/collections/CollectionSchemaView.scss b/src/client/views/collections/CollectionSchemaView.scss index 6eabbe17c..cfdb3ab22 100644 --- a/src/client/views/collections/CollectionSchemaView.scss +++ b/src/client/views/collections/CollectionSchemaView.scss @@ -1,6 +1,7 @@ @import "../globalCssVariables"; + .collectionSchemaView-container { border-width: $COLLECTION_BORDER_WIDTH; border-color : $intermediate-color; @@ -10,6 +11,10 @@ position: absolute; width: 100%; height: 100%; + + .collectionSchemaView-cellContents { + height: $MAX_ROW_HEIGHT; + } .collectionSchemaView-previewRegion { position: relative; @@ -104,7 +109,7 @@ } .rt-tr-group { direction: ltr; - max-height: 44px; + max-height: $MAX_ROW_HEIGHT; } .rt-td { border-width: 1px; @@ -136,7 +141,7 @@ } .ReactTable .rt-th, .ReactTable .rt-td { - max-height: 44; + max-height: $MAX_ROW_HEIGHT; padding: 3px 7px; font-size: 13px; text-align: center; diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index b61eb342d..90077b053 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -5,6 +5,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, observable, untracked } from "mobx"; import { observer } from "mobx-react"; import ReactTable, { CellInfo, ComponentPropsGetterR, ReactTableDefaults } from "react-table"; +import { MAX_ROW_HEIGHT } from '../../views/globalCssVariables.scss' import "react-table/react-table.css"; import { Document } from "../../../fields/Document"; import { Field, Opt } from "../../../fields/Field"; @@ -99,11 +100,11 @@ export class CollectionSchemaView extends CollectionSubView { return false; }; return ( -
+
{ let field = props.Document.Get(props.fieldKey); if (field && field instanceof Field) { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx index 8868f7df0..20c5a84bf 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx @@ -23,10 +23,10 @@ export class CollectionFreeFormLinkView extends React.Component { if (super.drop(e, de) && de.data instanceof DragManager.DocumentDragData) { - console.log("DROP Aat " + de.x + " off " + de.data.xOffset); const [x, y] = this.getTransform().transformPoint(de.x - de.data.xOffset, de.y - de.data.yOffset); if (de.data.droppedDocuments.length) { let dragDoc = de.data.droppedDocuments[0]; let dropX = dragDoc.GetNumber(KeyStore.X, 0); let dropY = dragDoc.GetNumber(KeyStore.Y, 0); de.data.droppedDocuments.map(d => { - let minimized = d.GetBoolean(KeyStore.Minimized, false); - d.SetNumber(KeyStore.X, x + (d.GetNumber(KeyStore.X, 0) - (minimized ? d.GetNumber(KeyStore.MinimizedX, 0) : 0)) - dropX); - d.SetNumber(KeyStore.Y, y + (d.GetNumber(KeyStore.Y, 0) - (minimized ? d.GetNumber(KeyStore.MinimizedY, 0) : 0)) - dropY); - if (!minimized) { + d.SetNumber(KeyStore.X, x + (d.GetNumber(KeyStore.X, 0)) - dropX); + d.SetNumber(KeyStore.Y, y + (d.GetNumber(KeyStore.Y, 0)) - dropY); + if (!d.GetBoolean(KeyStore.IsMinimized, false)) { if (!d.GetNumber(KeyStore.Width, 0)) { d.SetNumber(KeyStore.Width, 300); } @@ -264,7 +263,9 @@ export class CollectionFreeFormView extends CollectionSubView { let docviews = this.props.Document.GetList(this.props.fieldKey, [] as Document[]).filter(doc => doc).reduce((prev, doc) => { var page = doc.GetNumber(KeyStore.Page, -1); if (page === curPage || page === -1) { - prev.push(); + let minim = doc.GetT(KeyStore.IsMinimized, BooleanField); + if (minim === undefined || (minim && !minim.Data)) + prev.push(); } return prev; }, [] as JSX.Element[]); diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 8b94374fa..bf918beba 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -208,12 +208,11 @@ export class MarqueeView extends React.Component let selRect = this.Bounds; let selection: Document[] = []; this.props.activeDocuments().map(doc => { - let minimized = doc.GetBoolean(KeyStore.Minimized, false); var z = doc.GetNumber(KeyStore.Zoom, 1); - var x = doc.GetNumber(KeyStore.X, 0) + (minimized ? doc.GetNumber(KeyStore.MinimizedX, 0) : 0); - var y = doc.GetNumber(KeyStore.Y, 0) + (minimized ? doc.GetNumber(KeyStore.MinimizedY, 0) : 0); - var w = minimized ? MINIMIZED_ICON_SIZE : doc.Width() / z; - var h = minimized ? MINIMIZED_ICON_SIZE : doc.Height() / z; + var x = doc.GetNumber(KeyStore.X, 0); + var y = doc.GetNumber(KeyStore.Y, 0); + var w = doc.Width() / z; + var h = doc.Height() / z; if (this.intersectRect({ left: x, top: y, width: w, height: h }, selRect)) { selection.push(doc); } diff --git a/src/client/views/globalCssVariables.scss b/src/client/views/globalCssVariables.scss index f154f8158..4f68b71b0 100644 --- a/src/client/views/globalCssVariables.scss +++ b/src/client/views/globalCssVariables.scss @@ -24,8 +24,10 @@ $docDecorations-zindex: 998; // then doc decorations appear over everything else $remoteCursors-zindex: 997; // ... not sure what level the remote cursors should go -- is this right? $COLLECTION_BORDER_WIDTH: 1; $MINIMIZED_ICON_SIZE:25; +$MAX_ROW_HEIGHT: 44px; :export { contextMenuZindex: $contextMenu-zindex; COLLECTION_BORDER_WIDTH: $COLLECTION_BORDER_WIDTH; MINIMIZED_ICON_SIZE: $MINIMIZED_ICON_SIZE; + MAX_ROW_HEIGHT: $MAX_ROW_HEIGHT; } \ No newline at end of file diff --git a/src/client/views/globalCssVariables.scss.d.ts b/src/client/views/globalCssVariables.scss.d.ts index cc77d987a..9788d31f7 100644 --- a/src/client/views/globalCssVariables.scss.d.ts +++ b/src/client/views/globalCssVariables.scss.d.ts @@ -3,6 +3,7 @@ interface IGlobalScss { contextMenuZindex: string; // context menu shows up over everything COLLECTION_BORDER_WIDTH: string; MINIMIZED_ICON_SIZE: string; + MAX_ROW_HEIGHT: string; } declare const globalCssVariables: IGlobalScss; diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index a3689414d..1d42b3899 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -46,10 +46,10 @@ export class CollectionFreeFormDocumentView extends React.Component this.props.ScreenToLocalTransform() @@ -57,8 +57,8 @@ export class CollectionFreeFormDocumentView extends React.Component this.nativeWidth > 0 ? this.width / this.nativeWidth : 1; - panelWidth = () => this.isMinimized ? 10 : this.props.PanelWidth(); - panelHeight = () => this.isMinimized ? 10 : this.props.PanelHeight(); + panelWidth = () => this.props.PanelWidth(); + panelHeight = () => this.props.PanelHeight(); @computed get docView() { @@ -70,19 +70,17 @@ export class CollectionFreeFormDocumentView extends React.Component; } - get isMinimized() { return this.props.Document.GetBoolean(KeyStore.Minimized, false); } - render() { let zoomFade = 1; //var zoom = doc.GetNumber(KeyStore.Zoom, 1); - let transform = this.getTransform().scale(this.contentScaling()).inverse(); - var [sptX, sptY] = transform.transformPoint(0, 0); - let [bptX, bptY] = transform.transformPoint(this.props.PanelWidth(), this.props.PanelHeight()); - let w = bptX - sptX; - //zoomFade = area < 100 || area > 800 ? Math.max(0, Math.min(1, 2 - 5 * (zoom < this.scale ? this.scale / zoom : zoom / this.scale))) : 1; - let fadeUp = .75 * 1800; - let fadeDown = .075 * 1800; - zoomFade = w < fadeDown /* || w > fadeUp */ ? Math.max(0, Math.min(1, 2 - (w < fadeDown ? fadeDown / w : w / fadeUp))) : 1; + // let transform = this.getTransform().scale(this.contentScaling()).inverse(); + // var [sptX, sptY] = transform.transformPoint(0, 0); + // let [bptX, bptY] = transform.transformPoint(this.props.PanelWidth(), this.props.PanelHeight()); + // let w = bptX - sptX; + // //zoomFade = area < 100 || area > 800 ? Math.max(0, Math.min(1, 2 - 5 * (zoom < this.scale ? this.scale / zoom : zoom / this.scale))) : 1; + // let fadeUp = .75 * 1800; + // let fadeDown = .075 * 1800; + // zoomFade = w < fadeDown /* || w > fadeUp */ ? Math.max(0, Math.min(1, 2 - (w < fadeDown ? fadeDown / w : w / fadeUp))) : 1; return (
Error loading layout keys

; } return ; @@ -189,10 +179,10 @@ export class DocumentView extends React.Component { document.removeEventListener("pointermove", this.onPointerMove); document.removeEventListener("pointerup", this.onPointerUp); e.stopPropagation(); - if (!SelectionManager.IsSelected(this) && e.button !== 2 && - Math.abs(e.clientX - this._downX) < 4 && Math.abs(e.clientY - this._downY) < 4) { - SelectionManager.SelectDoc(this, e.ctrlKey); - } + if (!SelectionManager.IsSelected(this) && e.button !== 2) + if (Math.abs(e.clientX - this._downX) < 4 && Math.abs(e.clientY - this._downY) < 4) { + SelectionManager.SelectDoc(this, e.ctrlKey); + } } stopPropagation = (e: React.SyntheticEvent) => { e.stopPropagation(); @@ -221,13 +211,33 @@ export class DocumentView extends React.Component { ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15); } + @action createIcon = (layoutString: string): void => { + let iconDoc = Documents.IconDocument(layoutString); + iconDoc.SetBoolean(KeyStore.IsMinimized, false); + iconDoc.SetNumber(KeyStore.NativeWidth, 0); + iconDoc.SetNumber(KeyStore.NativeHeight, 0); + iconDoc.Set(KeyStore.Prototype, this.props.Document); + iconDoc.Set(KeyStore.MaximizedDoc, this.props.Document); + this.props.Document.Set(KeyStore.MinimizedDoc, iconDoc); + this.props.addDocument && this.props.addDocument(iconDoc, false); + } + @action - public minimize = (where: number[]): void => { - this.props.Document.SetBoolean(KeyStore.Minimized, true); - if (where[0] !== 0 || where[1] !== 0) - this.props.Document.SetNumber(KeyStore.MinimizedX, where[0]); - if (where[1] !== 0 || where[0] !== 0) - this.props.Document.SetNumber(KeyStore.MinimizedY, where[1]); + public minimize = (): void => { + this.props.Document.SetBoolean(KeyStore.IsMinimized, true); + this.props.Document.GetAsync(KeyStore.MinimizedDoc, mindoc => { + if (mindoc === undefined) { + this.props.Document.GetAsync(KeyStore.BackgroundLayout, field => { + if (field instanceof TextField) this.createIcon(field.Data); + else this.props.Document.GetAsync(KeyStore.Layout, field => { + if (field instanceof TextField) this.createIcon(field.Data); + }); + }); + } + else if (mindoc instanceof Document) { + this.props.addDocument && this.props.addDocument(mindoc, false); + } + }); } @undoBatch @@ -295,7 +305,6 @@ export class DocumentView extends React.Component { } e.preventDefault(); - !this.isMinimized() && ContextMenu.Instance.addItem({ description: "Minimize", event: () => this.minimize([0, 0]) }); ContextMenu.Instance.addItem({ description: "Full Screen", event: this.fullScreenClicked }); ContextMenu.Instance.addItem({ description: "Fields", event: this.fieldsClicked }); ContextMenu.Instance.addItem({ description: "Center", event: () => this.props.focus(this.props.Document) }); @@ -309,9 +318,6 @@ export class DocumentView extends React.Component { SelectionManager.SelectDoc(this, false); } - @action - expand = (e: React.MouseEvent) => { this.props.Document.SetBoolean(KeyStore.Minimized, false); SelectionManager.SelectDoc(this, e.ctrlKey); } - isMinimized = () => this.props.Document.GetBoolean(KeyStore.Minimized, false); isSelected = () => SelectionManager.IsSelected(this); select = (ctrlPressed: boolean) => SelectionManager.SelectDoc(this, ctrlPressed); @@ -319,27 +325,12 @@ export class DocumentView extends React.Component { @computed get nativeHeight() { return this.props.Document.GetNumber(KeyStore.NativeHeight, 0); } @computed get contents() { return (); } - @computed get minimizedIcon() { - let button = this.layout.indexOf("PDFBox") !== -1 ? faFilePdf : - this.layout.indexOf("ImageBox") !== -1 ? faImage : - this.layout.indexOf("Formatted") !== -1 ? faStickyNote : - this.layout.indexOf("Video") !== -1 ? faFilm : - this.layout.indexOf("Collection") !== -1 ? faObjectGroup : - faCaretUp; - return - } render() { var scaling = this.props.ContentScaling(); var nativeHeight = this.nativeHeight > 0 ? this.nativeHeight.toString() + "px" : "100%"; var nativeWidth = this.nativeWidth > 0 ? this.nativeWidth.toString() + "px" : "100%"; - if (this.isMinimized()) { - return ( -
- {this.minimizedIcon} -
); - } return (
{ else if (field instanceof ImageField) { return ; } + else if (field instanceof IconField) { + return ; + } else if (field instanceof VideoField) { return ; } diff --git a/src/client/views/nodes/IconBox.scss b/src/client/views/nodes/IconBox.scss new file mode 100644 index 000000000..ce0ee2e09 --- /dev/null +++ b/src/client/views/nodes/IconBox.scss @@ -0,0 +1,12 @@ + +@import "../globalCssVariables"; +.iconBox-container { + position: absolute; + left:0; + top:0; + svg { + width: 100% !important; + height: 100%; + background: white; + } +} \ No newline at end of file diff --git a/src/client/views/nodes/IconBox.tsx b/src/client/views/nodes/IconBox.tsx new file mode 100644 index 000000000..5ada2186d --- /dev/null +++ b/src/client/views/nodes/IconBox.tsx @@ -0,0 +1,90 @@ +import React = require("react"); +import { library } from '@fortawesome/fontawesome-svg-core'; +import { faCaretUp, faFilePdf, faFilm, faImage, faObjectGroup, faStickyNote } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { action, computed } from "mobx"; +import { observer } from "mobx-react"; +import { Document } from '../../../fields/Document'; +import { IconField } from "../../../fields/IconFIeld"; +import { KeyStore } from "../../../fields/KeyStore"; +import { SelectionManager } from "../../util/SelectionManager"; +import { FieldView, FieldViewProps } from './FieldView'; +import "./IconBox.scss"; + + +library.add(faCaretUp); +library.add(faObjectGroup); +library.add(faStickyNote); +library.add(faFilePdf); +library.add(faFilm); + +@observer +export class IconBox extends React.Component { + public static LayoutString() { return FieldView.LayoutString(IconBox); } + + @computed get maximized() { return this.props.Document.GetT(KeyStore.MaximizedDoc, Document); } + @computed get layout(): string { return this.props.Document.GetData(this.props.fieldKey, IconField, "

Error loading layout data

" as string); } + @computed get minimizedIcon() { return IconBox.DocumentIcon(this.layout); } + + public static DocumentIcon(layout: string) { + let button = layout.indexOf("PDFBox") !== -1 ? faFilePdf : + layout.indexOf("ImageBox") !== -1 ? faImage : + layout.indexOf("Formatted") !== -1 ? faStickyNote : + layout.indexOf("Video") !== -1 ? faFilm : + layout.indexOf("Collection") !== -1 ? faObjectGroup : + faCaretUp; + return + } + + animateTransition(icon: number[], targ: number[], width: number, height: number, stime: number, target: Document, maximizing: boolean) { + setTimeout(() => { + let now = Date.now(); + let progress = Math.min(1, (now - stime) / 200); + let pval = maximizing ? + [icon[0] + (targ[0] - icon[0]) * progress, icon[1] + (targ[1] - icon[1]) * progress] : + [targ[0] + (icon[0] - targ[0]) * progress, targ[1] + (icon[1] - targ[1]) * progress]; + target.SetNumber(KeyStore.Width, maximizing ? 25 + (width - 25) * progress : width + (25 - width) * progress); + target.SetNumber(KeyStore.Height, maximizing ? 25 + (height - 25) * progress : height + (25 - height) * progress); + target.SetNumber(KeyStore.X, pval[0]); + target.SetNumber(KeyStore.Y, pval[1]); + if (now < stime + 200) { + this.animateTransition(icon, targ, width, height, stime, target, maximizing); + } + else { + if (!maximizing) { + target.SetBoolean(KeyStore.IsMinimized, true); + target.SetNumber(KeyStore.X, targ[0]); + target.SetNumber(KeyStore.Y, targ[1]); + target.SetNumber(KeyStore.Width, width); + target.SetNumber(KeyStore.Height, height); + } + this._completed = true; + } + }, + 2); + } + + _completed = true; + + @action + public toggleMinimize = (): void => { + SelectionManager.DeselectAll(); + if (this.maximized instanceof Document && this._completed) { + this._completed = false; + let minimized = this.maximized.GetBoolean(KeyStore.IsMinimized, false); + this.maximized.SetBoolean(KeyStore.IsMinimized, false); + this.animateTransition( + [this.props.Document.GetNumber(KeyStore.X, 0), this.props.Document.GetNumber(KeyStore.Y, 0)], + [this.maximized.GetNumber(KeyStore.X, 0), this.maximized.GetNumber(KeyStore.Y, 0)], + this.maximized.GetNumber(KeyStore.Width, 0), this.maximized.GetNumber(KeyStore.Width, 0), + Date.now(), this.maximized, minimized); + } + } + + render() { + return ( +
+ {this.minimizedIcon} +
); + } +} \ No newline at end of file diff --git a/src/fields/IconFIeld.ts b/src/fields/IconFIeld.ts new file mode 100644 index 000000000..a6694cc49 --- /dev/null +++ b/src/fields/IconFIeld.ts @@ -0,0 +1,25 @@ +import { BasicField } from "./BasicField"; +import { FieldId } from "./Field"; +import { Types } from "../server/Message"; + +export class IconField extends BasicField { + constructor(data: string = "", id?: FieldId, save: boolean = true) { + super(data, save, id); + } + + ToScriptString(): string { + return `new IconField("${this.Data}")`; + } + + Copy() { + return new IconField(this.Data); + } + + ToJson() { + return { + type: Types.Icon, + data: this.Data, + id: this.Id + }; + } +} \ No newline at end of file diff --git a/src/fields/KeyStore.ts b/src/fields/KeyStore.ts index ff2f31003..a347f8bcf 100644 --- a/src/fields/KeyStore.ts +++ b/src/fields/KeyStore.ts @@ -4,8 +4,6 @@ export namespace KeyStore { export const Prototype = new Key("Prototype"); export const X = new Key("X"); export const Y = new Key("Y"); - export const MinimizedX = new Key("MinimizedX"); - export const MinimizedY = new Key("MinimizedY"); export const Page = new Key("Page"); export const Title = new Key("Title"); export const Author = new Key("Author"); @@ -47,14 +45,16 @@ export namespace KeyStore { export const OptionalRightCollection = new Key("OptionalRightCollection"); export const Archives = new Key("Archives"); export const Workspaces = new Key("Workspaces"); - export const Minimized = new Key("Minimized"); + export const IsMinimized = new Key("IsMinimized"); + export const MinimizedDoc = new Key("MinimizedDoc"); + export const MaximizedDoc = new Key("MaximizedDoc"); export const CopyDraggedItems = new Key("CopyDraggedItems"); - export const KeyList: Key[] = [Prototype, X, Y, MinimizedX, MinimizedY, Page, Title, Author, PanX, PanY, Scale, NativeWidth, NativeHeight, + export const KeyList: Key[] = [Prototype, X, Y, Page, Title, Author, PanX, PanY, Scale, NativeWidth, NativeHeight, Width, Height, ZIndex, Zoom, Data, Annotations, ViewType, Layout, BackgroundColor, BackgroundLayout, OverlayLayout, LayoutKeys, LayoutFields, ColumnsKey, SchemaSplitPercentage, Caption, ActiveWorkspace, DocumentText, BrushingDocs, LinkedToDocs, LinkedFromDocs, LinkDescription, LinkTags, Thumbnail, ThumbnailPage, CurPage, AnnotationOn, NumPages, Ink, Cursors, OptionalRightCollection, - Archives, Workspaces, Minimized, CopyDraggedItems + Archives, Workspaces, IsMinimized, MinimizedDoc, MaximizedDoc, CopyDraggedItems ]; export function KeyLookup(keyid: string) { for (const key of KeyList) { diff --git a/src/server/Message.ts b/src/server/Message.ts index bbe4ffcad..15916ef12 100644 --- a/src/server/Message.ts +++ b/src/server/Message.ts @@ -14,7 +14,7 @@ export class Message { } export enum Types { - Number, List, Key, Image, Web, Document, Text, RichText, DocumentReference, + Number, List, Key, Image, Web, Document, Text, Icon, RichText, DocumentReference, Html, Video, Audio, Ink, PDF, Tuple, HistogramOp, Boolean, Script, } diff --git a/src/server/ServerUtil.ts b/src/server/ServerUtil.ts index 818230c1a..79ca5e55d 100644 --- a/src/server/ServerUtil.ts +++ b/src/server/ServerUtil.ts @@ -18,6 +18,7 @@ import { NumberField } from "./../fields/NumberField"; import { RichTextField } from "./../fields/RichTextField"; import { TextField } from "./../fields/TextField"; import { Transferable, Types } from "./Message"; +import { IconField } from "../fields/IconFIeld"; export class ServerUtils { public static prepend(extension: string): string { @@ -37,6 +38,7 @@ export class ServerUtils { case Types.Boolean: return new BooleanField(json.data, json.id, false); case Types.Number: return new NumberField(json.data, json.id, false); case Types.Text: return new TextField(json.data, json.id, false); + case Types.Icon: return new IconField(json.data, json.id, false); case Types.Html: return new HtmlField(json.data, json.id, false); case Types.Web: return new WebField(new URL(json.data), json.id, false); case Types.RichText: return new RichTextField(json.data, json.id, false); -- cgit v1.2.3-70-g09d2 From 5ffb2f404a6a3da851c0fe7318b73f5c7723c3d7 Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Tue, 23 Apr 2019 01:05:12 -0400 Subject: Did most of Documents and some other stuff --- src/Utils.ts | 19 +- src/client/documents/Documents.ts | 202 +++++++++------------ src/client/northstar/dash-fields/HistogramField.ts | 2 +- .../views/nodes/CollectionFreeFormDocumentView.tsx | 2 +- src/client/views/nodes/DocumentContentsView.tsx | 2 +- src/new_fields/Doc.ts | 31 +++- src/new_fields/List.ts | 2 +- src/new_fields/Types.ts | 2 +- src/new_fields/util.ts | 12 +- 9 files changed, 139 insertions(+), 135 deletions(-) (limited to 'src/client/northstar') diff --git a/src/Utils.ts b/src/Utils.ts index 066d653f5..59ff45dc9 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -86,13 +86,20 @@ export class Utils { } } -export function OmitKeys(obj: any, keys: any, addKeyFunc?: (dup: any) => void) { +export function OmitKeys(obj: any, keys: string[], addKeyFunc?: (dup: any) => void): { omit: any, extract: any } { + const omit: any = { ...obj }; + const extract: any = {}; + keys.forEach(key => { + extract[key] = omit[key]; + delete omit[key]; + }); + addKeyFunc && addKeyFunc(omit); + return { omit, extract }; +} + +export function WithKeys(obj: any, keys: string[], addKeyFunc?: (dup: any) => void) { var dup: any = {}; - for (var key in obj) { - if (keys.indexOf(key) === -1) { - dup[key] = obj[key]; - } - } + keys.forEach(key => dup[key] = obj[key]); addKeyFunc && addKeyFunc(dup); return dup; } diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index b0bb74d89..a145a76c9 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -1,20 +1,6 @@ -import { AudioField } from "../../fields/AudioField"; -import { Document } from "../../fields/Document"; -import { Field, Opt } from "../../fields/Field"; -import { HtmlField } from "../../fields/HtmlField"; -import { ImageField } from "../../fields/ImageField"; -import { InkField, StrokeData } from "../../fields/InkField"; -import { Key } from "../../fields/Key"; -import { KeyStore } from "../../fields/KeyStore"; -import { ListField } from "../../fields/ListField"; -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"; import { CollectionView } from "../views/collections/CollectionView"; @@ -34,39 +20,47 @@ import { AttributeTransformationModel } from "../northstar/core/attribute/Attrib import { AggregateFunction } from "../northstar/model/idea/idea"; import { MINIMIZED_ICON_SIZE } from "../views/globalCssVariables.scss"; import { IconBox } from "../views/nodes/IconBox"; -import { IconField } from "../../fields/IconFIeld"; +import { Field, Doc, Opt } from "../../new_fields/Doc"; +import { OmitKeys } from "../../Utils"; +import { ImageField, VideoField, AudioField, PdfField, WebField } from "../../new_fields/URLField"; +import { HtmlField } from "../../new_fields/HtmlField"; +import { List } from "../../new_fields/List"; +import { Cast } from "../../new_fields/Types"; export interface DocumentOptions { x?: number; y?: number; - ink?: Map; + // ink?: Map; width?: number; height?: number; nativeWidth?: number; nativeHeight?: number; title?: string; - panx?: number; - pany?: number; + panX?: number; + panY?: number; page?: number; scale?: number; layout?: string; - layoutKeys?: Key[]; viewType?: number; backgroundColor?: string; copyDraggedItems?: boolean; + backgroundLayout?: string; + curPage?: number; + // [key: string]: Opt; } +const delegateKeys = ["x", "y", "width", "height", "panX", "panY"]; -export namespace Documents { - let textProto: Document; - let histoProto: Document; - let imageProto: Document; - let webProto: Document; - let collProto: Document; - let kvpProto: Document; - let videoProto: Document; - let audioProto: Document; - let pdfProto: Document; - let iconProto: Document; +export namespace Docs { + let textProto: Doc; + let histoProto: Doc; + let imageProto: Doc; + let webProto: Doc; + let collProto: Doc; + let kvpProto: Doc; + let videoProto: Doc; + let audioProto: Doc; + let pdfProto: Doc; + let iconProto: Doc; const textProtoId = "textProto"; const histoProtoId = "histoProto"; const pdfProtoId = "pdfProto"; @@ -92,110 +86,80 @@ export namespace Documents { iconProto = fields[iconProtoId] as Document || CreateIconPrototype(); }); } - function assignOptions(doc: Document, options: DocumentOptions): Document { - if (options.nativeWidth !== undefined) { doc.SetNumber(KeyStore.NativeWidth, options.nativeWidth); } - if (options.nativeHeight !== undefined) { doc.SetNumber(KeyStore.NativeHeight, options.nativeHeight); } - if (options.title !== undefined) { doc.SetText(KeyStore.Title, options.title); } - if (options.page !== undefined) { doc.SetNumber(KeyStore.Page, options.page); } - if (options.scale !== undefined) { doc.SetNumber(KeyStore.Scale, options.scale); } - if (options.width !== undefined) { doc.SetNumber(KeyStore.Width, options.width); } - if (options.height !== undefined) { doc.SetNumber(KeyStore.Height, options.height); } - if (options.viewType !== undefined) { doc.SetNumber(KeyStore.ViewType, options.viewType); } - if (options.backgroundColor !== undefined) { doc.SetText(KeyStore.BackgroundColor, options.backgroundColor); } - 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.copyDraggedItems !== undefined) { doc.SetBoolean(KeyStore.CopyDraggedItems, options.copyDraggedItems); } - return doc; - } - function assignToDelegate(doc: Document, options: DocumentOptions): Document { - if (options.x !== undefined) { doc.SetNumber(KeyStore.X, options.x); } - if (options.y !== undefined) { doc.SetNumber(KeyStore.Y, options.y); } - if (options.width !== undefined) { doc.SetNumber(KeyStore.Width, options.width); } - if (options.height !== undefined) { doc.SetNumber(KeyStore.Height, options.height); } - if (options.panx !== undefined) { doc.SetNumber(KeyStore.PanX, options.panx); } - if (options.pany !== undefined) { doc.SetNumber(KeyStore.PanY, options.pany); } - return doc; + function setupPrototypeOptions(protoId: string, title: string, layout: string, options: DocumentOptions): Doc { + return Doc.assign(new Doc(protoId, true), { ...options, title: title, layout: layout }); } - - function setupPrototypeOptions(protoId: string, title: string, layout: string, options: DocumentOptions): Document { - return assignOptions(new Document(protoId), { ...options, title: title, layout: layout }); + function SetInstanceOptions(doc: Doc, options: DocumentOptions, value: U) { + const deleg = Doc.MakeDelegate(doc); + deleg.data = value; + return Doc.assign(deleg, options); } - function SetInstanceOptions(doc: Document, options: DocumentOptions, value: [T, { new(): U }] | Document, id?: string) { - var deleg = doc.MakeDelegate(id); - if (value instanceof Document) { - deleg.Set(KeyStore.Data, value); - } - else { - deleg.SetData(KeyStore.Data, value[0], value[1]); - } - return assignOptions(deleg, options); + function SetDelegateOptions(doc: Doc, options: DocumentOptions) { + const deleg = Doc.MakeDelegate(doc); + return Doc.assign(deleg, options); } - function CreateImagePrototype(): Document { + function CreateImagePrototype(): Doc { let imageProto = setupPrototypeOptions(imageProtoId, "IMAGE_PROTO", CollectionView.LayoutString("AnnotationsKey"), - { x: 0, y: 0, nativeWidth: 600, width: 300, layoutKeys: [KeyStore.Data, KeyStore.Annotations, KeyStore.Caption] }); - imageProto.SetText(KeyStore.BackgroundLayout, ImageBox.LayoutString()); - imageProto.SetNumber(KeyStore.CurPage, 0); + { x: 0, y: 0, nativeWidth: 600, width: 300, backgroundLayout: ImageBox.LayoutString(), curPage: 0 }); return imageProto; } - function CreateHistogramPrototype(): Document { + function CreateHistogramPrototype(): Doc { let histoProto = setupPrototypeOptions(histoProtoId, "HISTO PROTO", CollectionView.LayoutString("AnnotationsKey"), - { x: 0, y: 0, width: 300, height: 300, backgroundColor: "black", layoutKeys: [KeyStore.Data, KeyStore.Annotations, KeyStore.Caption] }); - histoProto.SetText(KeyStore.BackgroundLayout, HistogramBox.LayoutString()); + { x: 0, y: 0, width: 300, height: 300, backgroundColor: "black", backgroundLayout: HistogramBox.LayoutString() }); return histoProto; } - function CreateIconPrototype(): Document { + function CreateIconPrototype(): Doc { let iconProto = setupPrototypeOptions(iconProtoId, "ICON_PROTO", IconBox.LayoutString(), - { x: 0, y: 0, width: Number(MINIMIZED_ICON_SIZE), height: Number(MINIMIZED_ICON_SIZE), layoutKeys: [KeyStore.Data] }); + { x: 0, y: 0, width: Number(MINIMIZED_ICON_SIZE), height: Number(MINIMIZED_ICON_SIZE) }); return iconProto; } - function CreateTextPrototype(): Document { + function CreateTextPrototype(): Doc { let textProto = setupPrototypeOptions(textProtoId, "TEXT_PROTO", FormattedTextBox.LayoutString(), - { x: 0, y: 0, width: 300, height: 150, layoutKeys: [KeyStore.Data] }); + { x: 0, y: 0, width: 300, height: 150 }); return textProto; } - function CreatePdfPrototype(): Document { + function CreatePdfPrototype(): Doc { let pdfProto = setupPrototypeOptions(pdfProtoId, "PDF_PROTO", CollectionPDFView.LayoutString("AnnotationsKey"), - { x: 0, y: 0, nativeWidth: 1200, width: 300, layoutKeys: [KeyStore.Data, KeyStore.Annotations] }); - pdfProto.SetNumber(KeyStore.CurPage, 1); - pdfProto.SetText(KeyStore.BackgroundLayout, PDFBox.LayoutString()); + { x: 0, y: 0, nativeWidth: 1200, width: 300, backgroundLayout: PDFBox.LayoutString(), curPage: 1 }); return pdfProto; } - function CreateWebPrototype(): Document { + function CreateWebPrototype(): Doc { let webProto = setupPrototypeOptions(webProtoId, "WEB_PROTO", WebBox.LayoutString(), - { x: 0, y: 0, width: 300, height: 300, layoutKeys: [KeyStore.Data] }); + { x: 0, y: 0, width: 300, height: 300 }); return webProto; } - function CreateCollectionPrototype(): Document { + function CreateCollectionPrototype(): Doc { let collProto = setupPrototypeOptions(collProtoId, "COLLECTION_PROTO", CollectionView.LayoutString("DataKey"), - { panx: 0, pany: 0, scale: 1, width: 500, height: 500, layoutKeys: [KeyStore.Data] }); + { panX: 0, panY: 0, scale: 1, width: 500, height: 500 }); return collProto; } - function CreateKVPPrototype(): Document { + function CreateKVPPrototype(): Doc { let kvpProto = setupPrototypeOptions(kvpProtoId, "KVP_PROTO", KeyValueBox.LayoutString(), - { x: 0, y: 0, width: 300, height: 150, layoutKeys: [KeyStore.Data] }); + { x: 0, y: 0, width: 300, height: 150 }); return kvpProto; } - function CreateVideoPrototype(): Document { + function CreateVideoPrototype(): Doc { let videoProto = setupPrototypeOptions(videoProtoId, "VIDEO_PROTO", CollectionVideoView.LayoutString("AnnotationsKey"), - { x: 0, y: 0, nativeWidth: 600, width: 300, layoutKeys: [KeyStore.Data, KeyStore.Annotations, KeyStore.Caption] }); - videoProto.SetNumber(KeyStore.CurPage, 0); - videoProto.SetText(KeyStore.BackgroundLayout, VideoBox.LayoutString()); + { x: 0, y: 0, nativeWidth: 600, width: 300, backgroundLayout: VideoBox.LayoutString(), curPage: 0 }); return videoProto; } - function CreateAudioPrototype(): Document { + function CreateAudioPrototype(): Doc { let audioProto = setupPrototypeOptions(audioProtoId, "AUDIO_PROTO", AudioBox.LayoutString(), - { x: 0, y: 0, width: 300, height: 150, layoutKeys: [KeyStore.Data] }); + { x: 0, y: 0, width: 300, height: 150 }); return audioProto; } + function CreateInstance(proto: Doc, data: Field, options: DocumentOptions) { + const { omit: protoProps, extract: delegateProps } = OmitKeys(options, delegateKeys); + return SetDelegateOptions(SetInstanceOptions(proto, protoProps, data), delegateProps); + } export function ImageDocument(url: string, options: DocumentOptions = {}) { - return assignToDelegate(SetInstanceOptions(imageProto, options, [new URL(url), ImageField]).MakeDelegate(), { ...options, layoutKeys: [KeyStore.Data, KeyStore.Annotations, KeyStore.Caption] }); + return CreateInstance(imageProto, new ImageField(new URL(url)), options); // let doc = SetInstanceOptions(GetImagePrototype(), { ...options, layoutKeys: [KeyStore.Data, KeyStore.Annotations, KeyStore.Caption] }, // [new URL(url), ImageField]); // doc.SetText(KeyStore.Caption, "my caption..."); @@ -204,23 +168,23 @@ export namespace Documents { // return doc; } export function VideoDocument(url: string, options: DocumentOptions = {}) { - return assignToDelegate(SetInstanceOptions(videoProto, options, [new URL(url), VideoField]), options); + return CreateInstance(videoProto, new VideoField(new URL(url)), options); } export function AudioDocument(url: string, options: DocumentOptions = {}) { - return assignToDelegate(SetInstanceOptions(audioProto, options, [new URL(url), AudioField]), options); + return CreateInstance(audioProto, new AudioField(new URL(url)), options); } - export function HistogramDocument(histoOp: HistogramOperation, options: DocumentOptions = {}, id?: string, delegId?: string) { - return assignToDelegate(SetInstanceOptions(histoProto, options, [histoOp, HistogramField], id).MakeDelegate(delegId), options); + export function HistogramDocument(histoOp: HistogramOperation, options: DocumentOptions = {}) { + return CreateInstance(histoProto, new HistogramField(histoOp), options); } export function TextDocument(options: DocumentOptions = {}) { - return assignToDelegate(SetInstanceOptions(textProto, options, ["", TextField]).MakeDelegate(), options); + return CreateInstance(textProto, "", options); } export function IconDocument(icon: string, options: DocumentOptions = {}) { - return assignToDelegate(SetInstanceOptions(iconProto, { width: Number(MINIMIZED_ICON_SIZE), height: Number(MINIMIZED_ICON_SIZE), layoutKeys: [KeyStore.Data], layout: IconBox.LayoutString(), ...options }, [icon, IconField]), options); + return CreateInstance(iconProto, new IconField(icon), options); } export function PdfDocument(url: string, options: DocumentOptions = {}) { - return assignToDelegate(SetInstanceOptions(pdfProto, options, [new URL(url), PDFField]).MakeDelegate(), options); + return CreateInstance(pdfProto, new PdfField(new URL(url)), options); } export async function DBDocument(url: string, options: DocumentOptions = {}) { let schemaName = options.title ? options.title : "-no schema-"; @@ -248,35 +212,35 @@ export namespace Documents { return Documents.TreeDocument([], { width: 50, height: 100, title: schemaName }); } export function WebDocument(url: string, options: DocumentOptions = {}) { - return assignToDelegate(SetInstanceOptions(webProto, options, [new URL(url), WebField]).MakeDelegate(), options); + return CreateInstance(webProto, new WebField(new URL(url)), options); } export function HtmlDocument(html: string, options: DocumentOptions = {}) { - return assignToDelegate(SetInstanceOptions(webProto, options, [html, HtmlField]).MakeDelegate(), options); + return CreateInstance(webProto, new HtmlField(html), options); } - export function KVPDocument(document: Document, options: DocumentOptions = {}, id?: string) { - return assignToDelegate(SetInstanceOptions(kvpProto, options, document, id), options); + export function KVPDocument(document: Doc, options: DocumentOptions = {}) { + return CreateInstance(kvpProto, document, options); } - export function FreeformDocument(documents: Array, options: DocumentOptions, id?: string, makePrototype: boolean = true) { + export function FreeformDocument(documents: Array, options: DocumentOptions, makePrototype: boolean = true) { if (!makePrototype) { - return SetInstanceOptions(collProto, { ...options, viewType: CollectionViewType.Freeform }, [documents, ListField], id); + return SetInstanceOptions(collProto, { ...options, viewType: CollectionViewType.Freeform }, new List(documents)); } - return assignToDelegate(SetInstanceOptions(collProto, { ...options, viewType: CollectionViewType.Freeform }, [documents, ListField], id).MakeDelegate(), options); + return CreateInstance(collProto, new List(documents), { ...options, viewType: CollectionViewType.Freeform }); } - export function SchemaDocument(documents: Array, options: DocumentOptions, id?: string) { - return assignToDelegate(SetInstanceOptions(collProto, { ...options, viewType: CollectionViewType.Schema }, [documents, ListField], id), options); + export function SchemaDocument(documents: Array, options: DocumentOptions) { + return CreateInstance(collProto, new List(documents), { ...options, viewType: CollectionViewType.Schema }); } - export function TreeDocument(documents: Array, options: DocumentOptions, id?: string) { - return assignToDelegate(SetInstanceOptions(collProto, { ...options, viewType: CollectionViewType.Tree }, [documents, ListField], id), options); + export function TreeDocument(documents: Array, options: DocumentOptions) { + return CreateInstance(collProto, new List(documents), { ...options, viewType: CollectionViewType.Tree }); } - export function DockDocument(config: string, options: DocumentOptions, id?: string) { - return assignToDelegate(SetInstanceOptions(collProto, { ...options, viewType: CollectionViewType.Docking }, [config, TextField], id), options); + export function DockDocument(config: string, options: DocumentOptions) { + return CreateInstance(collProto, config, { ...options, viewType: CollectionViewType.Docking }); } - export function CaptionDocument(doc: Document) { - const captionDoc = doc.CreateAlias(); - captionDoc.SetText(KeyStore.OverlayLayout, FixedCaption()); - captionDoc.SetNumber(KeyStore.Width, doc.GetNumber(KeyStore.Width, 0)); - captionDoc.SetNumber(KeyStore.Height, doc.GetNumber(KeyStore.Height, 0)); + export function CaptionDocument(doc: Doc) { + const captionDoc = Doc.MakeAlias(doc); + captionDoc.overlayLayout = FixedCaption(); + captionDoc.width = Cast(doc.width, "number", 0); + captionDoc.height = Cast(doc.height, "number", 0); return captionDoc; } diff --git a/src/client/northstar/dash-fields/HistogramField.ts b/src/client/northstar/dash-fields/HistogramField.ts index c699691a4..932166b21 100644 --- a/src/client/northstar/dash-fields/HistogramField.ts +++ b/src/client/northstar/dash-fields/HistogramField.ts @@ -15,7 +15,7 @@ export class HistogramField extends BasicField { } toString(): string { - return JSON.stringify(OmitKeys(this.Data, ['Links', 'BrushLinks', 'Result', 'BrushColors', 'FilterModels', 'FilterOperand'])); + return JSON.stringify(OmitKeys(this.Data, ['Links', 'BrushLinks', 'Result', 'BrushColors', 'FilterModels', 'FilterOperand']).omit); } Copy(): Field { diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index c6eea5623..7b7b7e65e 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -71,7 +71,7 @@ export class CollectionFreeFormDocumentView extends DocComponentError loading layout data

"); } CreateBindings(): JsxBindings { - let bindings: JsxBindings = { props: OmitKeys(this.props, ['parentActive'], (obj: any) => obj.active = this.props.parentActive) }; + let bindings: JsxBindings = { props: OmitKeys(this.props, ['parentActive'], (obj: any) => obj.active = this.props.parentActive).omit }; return bindings; } diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 5ae095e68..987cb2cc4 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -4,7 +4,7 @@ import { autoObject, SerializationHelper, Deserializable } from "../client/util/ import { Utils } from "../Utils"; import { DocServer } from "../client/DocServer"; import { setter, getter, getField } from "./util"; -import { Cast, ToConstructor } from "./Types"; +import { Cast, ToConstructor, PromiseValue } from "./Types"; export type FieldId = string; export const HandleUpdate = Symbol("HandleUpdate"); @@ -54,7 +54,8 @@ export class Doc extends RefField { return doc; } - [key: string]: Field | FieldWaiting | undefined; + proto: FieldResult; + [key: string]: FieldResult; @serializable(alias("fields", map(autoObject()))) @observable @@ -92,6 +93,32 @@ export namespace Doc { proto[key] = value; } } + export function assign(doc: Doc, fields: Partial>>) { + for (const key in fields) { + if (fields.hasOwnProperty(key)) { + const value = fields[key]; + if (value !== undefined) { + doc[key] = value; + } + } + } + return doc; + } + + export function MakeAlias(doc: Doc) { + const alias = new Doc; + + PromiseValue(Cast(doc.proto, Doc)).then(proto => { + if (proto) { + alias.proto = proto; + } + }); + + return alias; + } + + export function MakeDelegate(doc: Doc): Doc; + export function MakeDelegate(doc: Opt): Opt; export function MakeDelegate(doc: Opt): Opt { if (!doc) { return undefined; diff --git a/src/new_fields/List.ts b/src/new_fields/List.ts index f3ec9e2c5..f01ac210a 100644 --- a/src/new_fields/List.ts +++ b/src/new_fields/List.ts @@ -33,4 +33,4 @@ class ListImpl extends ObjectField { private [Self] = this; } export type List = ListImpl & T[]; -export const List: { new (): List } = ListImpl as any; \ No newline at end of file +export const List: { new (fields?: T[]): List } = ListImpl as any; \ No newline at end of file diff --git a/src/new_fields/Types.ts b/src/new_fields/Types.ts index 246b0624e..55083765a 100644 --- a/src/new_fields/Types.ts +++ b/src/new_fields/Types.ts @@ -68,7 +68,7 @@ export function FieldValue(field: Opt | Promise>, def } export interface PromiseLike { - then(callback: (field: Opt | PromiseLike) => void): void; + then(callback: (field: Opt) => void): void; } export function PromiseValue(field: FieldResult): PromiseLike> { return field instanceof Promise ? field : { then(cb: ((field: Opt) => void)) { return cb(field); } }; diff --git a/src/new_fields/util.ts b/src/new_fields/util.ts index 3806044bd..2d9721b2e 100644 --- a/src/new_fields/util.ts +++ b/src/new_fields/util.ts @@ -2,6 +2,7 @@ import { UndoManager } from "../client/util/UndoManager"; import { Update, OnUpdate, Parent, ObjectField, RefField, Doc, Id, Field } from "./Doc"; import { SerializationHelper } from "../client/util/SerializationHelper"; import { ProxyField } from "./Proxy"; +import { FieldValue } from "./Types"; export function setter(target: any, prop: string | symbol | number, value: any, receiver: any): boolean { if (SerializationHelper.IsSerializing()) { @@ -61,11 +62,16 @@ export function getField(target: any, prop: string | number, ignoreProto: boolea return field.value(callback); } if (field === undefined && !ignoreProto) { - const proto = getField(target, "prototype", true); + const proto = getField(target, "proto", true); if (proto instanceof Doc) { let field = proto[prop]; - callback && callback(field === null ? undefined : field); - return field; + if (field instanceof Promise) { + callback && field.then(callback); + return undefined; + } else { + callback && callback(field); + return field; + } } } callback && callback(field); -- cgit v1.2.3-70-g09d2 From 3165f8a8a095a8c971144788fe40ff0d808c0c84 Mon Sep 17 00:00:00 2001 From: bob Date: Fri, 26 Apr 2019 15:11:42 -0400 Subject: fixed histograms? --- src/client/documents/Documents.ts | 2 +- src/client/northstar/dash-fields/HistogramField.ts | 94 ++++++++++------------ src/client/northstar/dash-nodes/HistogramBox.tsx | 51 ++++++------ .../northstar/operations/HistogramOperation.ts | 17 ++-- 4 files changed, 78 insertions(+), 86 deletions(-) (limited to 'src/client/northstar') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index ed76f32ff..8f873ef41 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -212,7 +212,7 @@ export namespace Docs { new AttributeTransformationModel(atmod, AggregateFunction.None), new AttributeTransformationModel(atmod, AggregateFunction.Count), new AttributeTransformationModel(atmod, AggregateFunction.Count)); - docs.push(Docs.HistogramDocument(histoOp, { width: 200, height: 200, title: attr.displayName! }, undefined, attr.displayName! + ".alias")); + docs.push(Docs.HistogramDocument(histoOp, { width: 200, height: 200, title: attr.displayName! })); } })); }); diff --git a/src/client/northstar/dash-fields/HistogramField.ts b/src/client/northstar/dash-fields/HistogramField.ts index 932166b21..baeaca1dd 100644 --- a/src/client/northstar/dash-fields/HistogramField.ts +++ b/src/client/northstar/dash-fields/HistogramField.ts @@ -1,64 +1,54 @@ -import { action } from "mobx"; +import { observable } from "mobx"; +import { custom, serializable } from "serializr"; import { ColumnAttributeModel } from "../../../client/northstar/core/attribute/AttributeModel"; import { AttributeTransformationModel } from "../../../client/northstar/core/attribute/AttributeTransformationModel"; import { HistogramOperation } from "../../../client/northstar/operations/HistogramOperation"; -import { BasicField } from "../../../fields/BasicField"; -import { Field, FieldId } from "../../../fields/Field"; +import { ObjectField } from "../../../new_fields/Doc"; import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils"; -import { Types } from "../../../server/Message"; import { OmitKeys } from "../../../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(OmitKeys(this.Data, ['Links', 'BrushLinks', 'Result', 'BrushColors', 'FilterModels', 'FilterOperand']).omit); - } - - Copy(): Field { - return new HistogramField(this.Data.Copy()); +import { Deserializable } from "../../util/SerializationHelper"; +function serialize(field: HistogramField) { + return OmitKeys(field.HistoOp, ['Links', 'BrushLinks', 'Result', 'BrushColors', 'FilterModels', 'FilterOperand']).omit +} + +function deserialize(jp: any) { + 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)); + } } - - ToScriptString(): string { - return `new HistogramField("${this.Data}")`; + return new HistogramField(HistogramOperation.Empty); +} + +@Deserializable("histogramField") +export class HistogramField extends ObjectField { + @serializable(custom(serialize, deserialize)) @observable public readonly HistoOp: HistogramOperation; + constructor(data?: HistogramOperation) { + super(); + this.HistoOp = data ? data : HistogramOperation.Empty; } - - ToJson() { - return { - type: Types.HistogramOp, - data: this.toString(), - id: this.Id - }; + toString(): string { + return JSON.stringify(OmitKeys(this.HistoOp, ['Links', 'BrushLinks', 'Result', 'BrushColors', 'FilterModels', 'FilterOperand']).omit); } - @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); + Copy(): HistogramField { + return new HistogramField(this.HistoOp.Copy()); } } \ 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 e2ecc8c83..4a65b14cf 100644 --- a/src/client/northstar/dash-nodes/HistogramBox.tsx +++ b/src/client/northstar/dash-nodes/HistogramBox.tsx @@ -2,9 +2,6 @@ import React = require("react"); 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"; -import { Document } from "../../../fields/Document"; -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"; @@ -21,6 +18,9 @@ import "./HistogramBox.scss"; import { HistogramBoxPrimitives } from './HistogramBoxPrimitives'; import { HistogramLabelPrimitives } from "./HistogramLabelPrimitives"; import { StyleConstants } from "../utils/StyleContants"; +import { NumCast, Cast } from "../../../new_fields/Types"; +import { listSpec } from "../../../new_fields/Schema"; +import { Doc, Id } from "../../../new_fields/Doc"; @observer @@ -50,9 +50,9 @@ export class HistogramBox extends React.Component { @action dropX = (e: Event, de: DragManager.DropEvent) => { if (de.data instanceof DragManager.DocumentDragData) { - let h = de.data.draggedDocuments[0].GetT(KeyStore.Data, HistogramField); - if (h && h !== FieldWaiting) { - this.HistoOp.X = h.Data.X; + let h = Cast(de.data.draggedDocuments[0].data, HistogramField); + if (h) { + this.HistoOp.X = h.HistoOp.X; } e.stopPropagation(); e.preventDefault(); @@ -61,9 +61,9 @@ export class HistogramBox extends React.Component { @action dropY = (e: Event, de: DragManager.DropEvent) => { if (de.data instanceof DragManager.DocumentDragData) { - let h = de.data.draggedDocuments[0].GetT(KeyStore.Data, HistogramField); - if (h && h !== FieldWaiting) { - this.HistoOp.Y = h.Data.X; + let h = Cast(de.data.draggedDocuments[0].data, HistogramField); + if (h) { + this.HistoOp.Y = h.HistoOp.X; } e.stopPropagation(); e.preventDefault(); @@ -113,32 +113,35 @@ export class HistogramBox extends React.Component { } } - activateHistogramOperation(catalog?: Catalog) { + async activateHistogramOperation(catalog?: Catalog) { if (catalog) { - this.props.Document.GetTAsync(this.props.fieldKey, HistogramField).then((histoOp: Opt) => runInAction(() => { - this.HistoOp = histoOp ? histoOp.Data : HistogramOperation.Empty; + let histoOp = await Cast(this.props.Document[this.props.fieldKey], HistogramField); + runInAction(() => { + this.HistoOp = histoOp ? histoOp.HistoOp : HistogramOperation.Empty; if (this.HistoOp !== HistogramOperation.Empty) { - reaction(() => this.props.Document.GetList(KeyStore.LinkedFromDocs, [] as Document[]), (docs) => this.HistoOp.Links.splice(0, this.HistoOp.Links.length, ...docs), { fireImmediately: true }); - reaction(() => this.props.Document.GetList(KeyStore.BrushingDocs, []).length, + reaction(() => Cast(this.props.Document.linkedFromDocs, listSpec(Doc), []), (docs) => this.HistoOp.Links.splice(0, this.HistoOp.Links.length, ...docs), { fireImmediately: true }); + reaction(() => Cast(this.props.Document.brushingDocs, listSpec(Doc), []).length, () => { - let brushingDocs = this.props.Document.GetList(KeyStore.BrushingDocs, [] as Document[]); - let proto = this.props.Document.GetPrototype() as Document; - 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[]); - return { l: brush, b: brushed[0].Id === proto.Id ? brushed[1] : brushed[0] }; - })); + let brushingDocs = Cast(this.props.Document.brushingDocs, listSpec(Doc), []); + const proto = this.props.Document.proto; + if (proto) { + this.HistoOp.BrushLinks.splice(0, this.HistoOp.BrushLinks.length, ...brushingDocs.map((brush, i) => { + brush.bckgroundColor = StyleConstants.BRUSH_COLORS[i % StyleConstants.BRUSH_COLORS.length]; + let brushed = Cast(brush.brushingDocs, listSpec(Doc), []); + return { l: brush, b: brushed[0][Id] === proto[Id] ? brushed[1] : brushed[0] }; + })); + } }, { 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.Document.GetNumber(KeyStore.Height, 0); - var w = this.props.isTopMost ? this.PanelWidth : this.props.Document.GetNumber(KeyStore.Width, 0); + var h = this.props.isTopMost ? this.PanelHeight : NumCast(this.props.Document.height); + var w = this.props.isTopMost ? this.PanelWidth : NumCast(this.props.Document.width); let loff = this.SizeConverter.LeftOffset; let toff = this.SizeConverter.TopOffset; let roff = this.SizeConverter.RightOffset; diff --git a/src/client/northstar/operations/HistogramOperation.ts b/src/client/northstar/operations/HistogramOperation.ts index 760106023..b6672eca3 100644 --- a/src/client/northstar/operations/HistogramOperation.ts +++ b/src/client/northstar/operations/HistogramOperation.ts @@ -1,7 +1,4 @@ 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"; @@ -16,12 +13,14 @@ import { AggregateFunction, AggregateParameters, Attribute, AverageAggregatePara import { ModelHelpers } from "../model/ModelHelpers"; import { ArrayUtil } from "../utils/ArrayUtil"; import { BaseOperation } from "./BaseOperation"; +import { Doc } from "../../../new_fields/Doc"; +import { Cast, NumCast } from "../../../new_fields/Types"; 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 Links: Doc[] = []; + @observable public BrushLinks: { l: Doc, b: Doc }[] = []; @observable public BrushColors: number[] = []; @observable public FilterModels: FilterModel[] = []; @@ -70,10 +69,10 @@ export class HistogramOperation extends BaseOperation implements IBaseFilterCons trace(); let brushes: string[] = []; this.BrushLinks.map(brushLink => { - let brushHistogram = brushLink.b.GetT(KeyStore.Data, HistogramField); - if (brushHistogram && brushHistogram !== FieldWaiting) { + let brushHistogram = Cast(brushLink.b.data, HistogramField); + if (brushHistogram) { let filterModels: FilterModel[] = []; - brushes.push(FilterModel.GetFilterModelsRecursive(brushHistogram.Data, new Set(), filterModels, false)); + brushes.push(FilterModel.GetFilterModelsRecursive(brushHistogram.HistoOp, new Set(), filterModels, false)); } }); return brushes; @@ -120,7 +119,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 => NumCast(e.l.backgroundColor)); return super.Update(); } } -- cgit v1.2.3-70-g09d2 From 513e9042ea815e964462e824d85fbd229381250f Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Sat, 27 Apr 2019 01:19:52 -0400 Subject: A bunch more stuff --- src/client/DocServer.ts | 6 +- .../northstar/core/brusher/IBaseBrushable.ts | 4 +- src/client/northstar/core/filter/FilterModel.ts | 17 ++- .../northstar/core/filter/IBaseFilterConsumer.ts | 4 +- src/client/northstar/dash-fields/HistogramField.ts | 3 +- src/client/util/TooltipTextMenu.tsx | 4 +- src/client/views/InkingStroke.tsx | 2 +- src/client/views/Main.tsx | 152 ++++++++++----------- .../views/collections/CollectionDockingView.tsx | 8 +- src/client/views/collections/CollectionPDFView.tsx | 10 +- .../views/collections/CollectionSchemaView.tsx | 4 +- .../views/collections/CollectionVideoView.tsx | 9 +- .../CollectionFreeFormLinkView.tsx | 20 +-- .../CollectionFreeFormLinksView.tsx | 63 +++++---- .../CollectionFreeFormRemoteCursors.tsx | 1 - src/client/views/nodes/IconBox.tsx | 12 +- 16 files changed, 165 insertions(+), 154 deletions(-) (limited to 'src/client/northstar') diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts index 02fd28a86..3f17baec6 100644 --- a/src/client/DocServer.ts +++ b/src/client/DocServer.ts @@ -1,5 +1,5 @@ import * as OpenSocket from 'socket.io-client'; -import { MessageStore, Types } from "./../server/Message"; +import { MessageStore, Types, Message } from "./../server/Message"; import { Opt, FieldWaiting, RefField, HandleUpdate } from '../new_fields/Doc'; import { Utils } from '../Utils'; import { SerializationHelper } from './util/SerializationHelper'; @@ -13,6 +13,10 @@ export namespace DocServer { return window.location.origin + extension; } + export function DeleteDatabase() { + Utils.Emit(_socket, MessageStore.DeleteAll, {}); + } + export async function GetRefField(id: string): Promise> { let cached = _cache[id]; if (cached === undefined) { diff --git a/src/client/northstar/core/brusher/IBaseBrushable.ts b/src/client/northstar/core/brusher/IBaseBrushable.ts index c46db4d22..87f4ba413 100644 --- a/src/client/northstar/core/brusher/IBaseBrushable.ts +++ b/src/client/northstar/core/brusher/IBaseBrushable.ts @@ -1,9 +1,9 @@ import { PIXIPoint } from '../../utils/MathUtil'; import { IEquatable } from '../../utils/IEquatable'; -import { Document } from '../../../../fields/Document'; +import { Doc } from '../../../../new_fields/Doc'; export interface IBaseBrushable extends IEquatable { - BrusherModels: Array; + BrusherModels: Array; BrushColors: Array; Position: PIXIPoint; Size: PIXIPoint; diff --git a/src/client/northstar/core/filter/FilterModel.ts b/src/client/northstar/core/filter/FilterModel.ts index e2ba3f652..6ab96b33d 100644 --- a/src/client/northstar/core/filter/FilterModel.ts +++ b/src/client/northstar/core/filter/FilterModel.ts @@ -2,10 +2,9 @@ import { ValueComparison } from "./ValueComparision"; import { Utils } from "../../utils/Utils"; import { IBaseFilterProvider } from "./IBaseFilterProvider"; import { FilterOperand } from "./FilterOperand"; -import { KeyStore } from "../../../../fields/KeyStore"; -import { FieldWaiting } from "../../../../fields/Field"; -import { Document } from "../../../../fields/Document"; import { HistogramField } from "../../dash-fields/HistogramField"; +import { Cast, FieldValue } from "../../../../new_fields/Types"; +import { Doc } from "../../../../new_fields/Doc"; export class FilterModel { public ValueComparisons: ValueComparison[]; @@ -52,12 +51,12 @@ export class FilterModel { 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); + let filterDoc = FieldValue(Cast(linkVm.linkedFrom, Doc)); + if (filterDoc) { + let filterHistogram = Cast(filterDoc.data, HistogramField); + if (filterHistogram) { + if (!visitedFilterProviders.has(filterHistogram.HistoOp)) { + let child = FilterModel.GetFilterModelsRecursive(filterHistogram.HistoOp, visitedFilterProviders, filterModels, false); if (child !== "") { // if (linkVm.IsInverted) { // child = "! " + child; diff --git a/src/client/northstar/core/filter/IBaseFilterConsumer.ts b/src/client/northstar/core/filter/IBaseFilterConsumer.ts index 59d7adf4c..e7549d113 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 { Document } from "../../../../fields/Document"; +import { Doc } from '../../../../new_fields/Doc'; export interface IBaseFilterConsumer extends IEquatable { FilterOperand: FilterOperand; - Links: Document[]; + Links: Doc[]; } export function instanceOfIBaseFilterConsumer(object: any): object is IBaseFilterConsumer { diff --git a/src/client/northstar/dash-fields/HistogramField.ts b/src/client/northstar/dash-fields/HistogramField.ts index baeaca1dd..118f4cf7f 100644 --- a/src/client/northstar/dash-fields/HistogramField.ts +++ b/src/client/northstar/dash-fields/HistogramField.ts @@ -7,8 +7,9 @@ import { ObjectField } from "../../../new_fields/Doc"; import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils"; import { OmitKeys } from "../../../Utils"; import { Deserializable } from "../../util/SerializationHelper"; + function serialize(field: HistogramField) { - return OmitKeys(field.HistoOp, ['Links', 'BrushLinks', 'Result', 'BrushColors', 'FilterModels', 'FilterOperand']).omit + return OmitKeys(field.HistoOp, ['Links', 'BrushLinks', 'Result', 'BrushColors', 'FilterModels', 'FilterOperand']).omit; } function deserialize(jp: any) { diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx index 4f0eb7d63..1b6647003 100644 --- a/src/client/util/TooltipTextMenu.tsx +++ b/src/client/util/TooltipTextMenu.tsx @@ -35,8 +35,8 @@ export class TooltipTextMenu { private fontStylesToName: Map; private fontSizeIndicator: HTMLSpanElement = document.createElement("span"); //dropdown doms - private fontSizeDom: Node; - private fontStyleDom: Node; + private fontSizeDom?: Node; + private fontStyleDom?: Node; constructor(view: EditorView, editorProps: FieldViewProps) { this.view = view; diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index 0f05da22c..616299146 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -1,8 +1,8 @@ import { observer } from "mobx-react"; import { observable } from "mobx"; import { InkingControl } from "./InkingControl"; -import { InkTool } from "../../fields/InkField"; import React = require("react"); +import { InkTool } from "../../new_fields/InkField"; interface StrokeProps { diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index c6b3f06d8..1e3d4e259 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -8,17 +8,12 @@ import * as React from 'react'; import * as ReactDOM from 'react-dom'; import Measure from 'react-measure'; import * as request from 'request'; -import { Document } from '../../fields/Document'; -import { Field, FieldWaiting, Opt, FIELD_WAITING } from '../../fields/Field'; -import { KeyStore } from '../../fields/KeyStore'; -import { ListField } from '../../fields/ListField'; import { WorkspacesMenu } from '../../server/authentication/controllers/WorkspacesMenu'; import { CurrentUserUtils } from '../../server/authentication/models/current_user_utils'; import { MessageStore } from '../../server/Message'; import { RouteStore } from '../../server/RouteStore'; -import { ServerUtils } from '../../server/ServerUtil'; -import { emptyDocFunction, emptyFunction, returnTrue, Utils, returnOne, returnZero } from '../../Utils'; -import { Documents } from '../documents/Documents'; +import { emptyFunction, returnTrue, Utils, returnOne, returnZero } from '../../Utils'; +import { Docs } from '../documents/Documents'; import { ColumnAttributeModel } from '../northstar/core/attribute/AttributeModel'; import { AttributeTransformationModel } from '../northstar/core/attribute/AttributeTransformationModel'; import { Gateway, NorthstarSettings } from '../northstar/manager/Gateway'; @@ -26,7 +21,6 @@ import { AggregateFunction, Catalog } from '../northstar/model/idea/idea'; import '../northstar/model/ModelExtensions'; import { HistogramOperation } from '../northstar/operations/HistogramOperation'; import '../northstar/utils/Extensions'; -import { Server } from '../Server'; import { SetupDrag, DragManager } from '../util/DragManager'; import { Transform } from '../util/Transform'; import { UndoManager } from '../util/UndoManager'; @@ -39,6 +33,10 @@ import { MainOverlayTextBox } from './MainOverlayTextBox'; import { DocumentView } from './nodes/DocumentView'; import { PreviewCursor } from './PreviewCursor'; import { SelectionManager } from '../util/SelectionManager'; +import { FieldResult, Field, Doc, Id, Opt } from '../../new_fields/Doc'; +import { Cast, FieldValue, StrCast } from '../../new_fields/Types'; +import { DocServer } from '../DocServer'; +import { listSpec } from '../../new_fields/Schema'; @observer @@ -48,11 +46,13 @@ export class Main extends React.Component { @observable public pwidth: number = 0; @observable public pheight: number = 0; - @computed private get mainContainer(): Document | undefined | FIELD_WAITING { - return CurrentUserUtils.UserDocument.GetT(KeyStore.ActiveWorkspace, Document); + @computed private get mainContainer(): Opt { + return FieldValue(Cast(CurrentUserUtils.UserDocument.activeWorkspace, Doc)); } - private set mainContainer(doc: Document | undefined | FIELD_WAITING) { - doc && CurrentUserUtils.UserDocument.Set(KeyStore.ActiveWorkspace, doc); + private set mainContainer(doc: Opt) { + if (doc) { + CurrentUserUtils.UserDocument.activeWorkspace = doc; + } } constructor(props: Readonly<{}>) { @@ -100,8 +100,8 @@ export class Main extends React.Component { if (window.location.pathname !== RouteStore.home) { let pathname = window.location.pathname.split("/"); CurrentUserUtils.MainDocId = pathname[pathname.length - 1]; - Server.GetField(CurrentUserUtils.MainDocId, action((field: Opt) => { - if (field instanceof Document) { + DocServer.GetRefField(CurrentUserUtils.MainDocId).then(action((field: Opt) => { + if (field instanceof Doc) { this.openWorkspace(field, true); } })); @@ -113,9 +113,9 @@ export class Main extends React.Component { window.addEventListener("drop", (e) => e.preventDefault(), false); // drop event handler window.addEventListener("dragover", (e) => e.preventDefault(), false); // drag event handler window.addEventListener("keydown", (e) => { - if (e.key == "Escape") { + if (e.key === "Escape") { DragManager.AbortDrag(); - SelectionManager.DeselectAll() + SelectionManager.DeselectAll(); } }, false); // drag event handler // click interactions for the context menu @@ -126,54 +126,55 @@ export class Main extends React.Component { }), true); } - initAuthenticationRouters = () => { + initAuthenticationRouters = async () => { // Load the user's active workspace, or create a new one if initial session after signup if (!CurrentUserUtils.MainDocId) { - CurrentUserUtils.UserDocument.GetTAsync(KeyStore.ActiveWorkspace, Document).then(doc => { - if (doc) { - CurrentUserUtils.MainDocId = doc.Id; - this.openWorkspace(doc); - } else { - this.createNewWorkspace(); - } - }); + const doc = await Cast(CurrentUserUtils.UserDocument.activeWorkspace, Doc); + if (doc) { + CurrentUserUtils.MainDocId = doc[Id]; + this.openWorkspace(doc); + } else { + this.createNewWorkspace(); + } } else { - Server.GetField(CurrentUserUtils.MainDocId).then(field => - field instanceof Document ? this.openWorkspace(field) : + DocServer.GetRefField(CurrentUserUtils.MainDocId).then(field => + field instanceof Doc ? this.openWorkspace(field) : this.createNewWorkspace(CurrentUserUtils.MainDocId)); } } @action - createNewWorkspace = (id?: string): void => { - CurrentUserUtils.UserDocument.GetTAsync>(KeyStore.Workspaces, ListField).then(action((list: Opt>) => { - if (list) { - let freeformDoc = Documents.FreeformDocument([], { x: 0, y: 400, title: "mini collection" }); - var dockingLayout = { content: [{ type: 'row', content: [CollectionDockingView.makeDocumentConfig(freeformDoc)] }] }; - let mainDoc = Documents.DockDocument(JSON.stringify(dockingLayout), { title: `Main Container ${list.Data.length + 1}` }, id); - list.Data.push(mainDoc); - CurrentUserUtils.MainDocId = mainDoc.Id; - // bcz: strangely, we need a timeout to prevent exceptions/issues initializing GoldenLayout (the rendering engine for Main Container) - setTimeout(() => { - this.openWorkspace(mainDoc); - let pendingDocument = Documents.SchemaDocument([], { title: "New Mobile Uploads" }); - mainDoc.Set(KeyStore.OptionalRightCollection, pendingDocument); - }, 0); - } - })); + createNewWorkspace = async (id?: string) => { + const list = Cast(CurrentUserUtils.UserDocument.workspaces, listSpec(Doc)); + if (list) { + let freeformDoc = Docs.FreeformDocument([], { x: 0, y: 400, title: "mini collection" }); + var dockingLayout = { content: [{ type: 'row', content: [CollectionDockingView.makeDocumentConfig(freeformDoc)] }] }; + let mainDoc = Docs.DockDocument(JSON.stringify(dockingLayout), { title: `Main Container ${list.length + 1}` }, id); + list.push(mainDoc); + CurrentUserUtils.MainDocId = mainDoc[Id]; + // bcz: strangely, we need a timeout to prevent exceptions/issues initializing GoldenLayout (the rendering engine for Main Container) + setTimeout(() => { + this.openWorkspace(mainDoc); + let pendingDocument = Docs.SchemaDocument([], { title: "New Mobile Uploads" }); + mainDoc.optionalRightCollection = pendingDocument; + }, 0); + } } @action - openWorkspace = (doc: Document, fromHistory = false): void => { + openWorkspace = async (doc: Doc, fromHistory = false) => { this.mainContainer = doc; - fromHistory || window.history.pushState(null, doc.Title, "/doc/" + doc.Id); - CurrentUserUtils.UserDocument.GetTAsync(KeyStore.OptionalRightCollection, Document).then(col => - // if there is a pending doc, and it has new data, show it (syip: we use a timeout to prevent collection docking view from being uninitialized) - setTimeout(() => - col && col.GetTAsync>(KeyStore.Data, ListField, (f: Opt>) => - f && f.Data.length > 0 && CollectionDockingView.Instance.AddRightSplit(col)) - , 100) - ); + fromHistory || window.history.pushState(null, StrCast(doc.title), "/doc/" + doc.Id); + const col = await Cast(CurrentUserUtils.UserDocument.optionalRightCollection, Doc); + // if there is a pending doc, and it has new data, show it (syip: we use a timeout to prevent collection docking view from being uninitialized) + setTimeout(async () => { + if (col) { + const l = Cast(col.data, listSpec(Doc)); + if (l && l.length > 0) { + CollectionDockingView.Instance.AddRightSplit(col); + } + } + }, 100); } @computed @@ -196,7 +197,7 @@ export class Main extends React.Component { PanelHeight={pheightFunc} isTopMost={true} selectOnLoad={false} - focus={emptyDocFunction} + focus={emptyFunction} parentActive={returnTrue} whenActiveChanged={emptyFunction} ContainingCollectionView={undefined} />} @@ -214,17 +215,17 @@ export class Main extends React.Component { let audiourl = "http://techslides.com/demos/samples/sample.mp3"; let videourl = "http://techslides.com/demos/sample-videos/small.mp4"; - 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._northstarSchemas, { width: 250, height: 400, title: "northstar schemas", copyDraggedItems: true })); - let addVideoNode = action(() => Documents.VideoDocument(videourl, { width: 200, title: "video node" })); - let addPDFNode = action(() => Documents.PdfDocument(pdfurl, { width: 200, height: 200, title: "a pdf doc" })); - let addImageNode = action(() => Documents.ImageDocument(imgurl, { width: 200, title: "an image of a cat" })); - let addWebNode = action(() => Documents.WebDocument(weburl, { width: 200, height: 200, title: "a sample web page" })); - let addAudioNode = action(() => Documents.AudioDocument(audiourl, { width: 200, height: 200, title: "audio node" })); + let addTextNode = action(() => Docs.TextDocument({ width: 200, height: 200, title: "a text note" })); + let addColNode = action(() => Docs.FreeformDocument([], { width: 200, height: 200, title: "a freeform collection" })); + let addSchemaNode = action(() => Docs.SchemaDocument([], { width: 200, height: 200, title: "a schema collection" })); + let addTreeNode = action(() => Docs.TreeDocument(this._northstarSchemas, { width: 250, height: 400, title: "northstar schemas", copyDraggedItems: true })); + let addVideoNode = action(() => Docs.VideoDocument(videourl, { width: 200, title: "video node" })); + let addPDFNode = action(() => Docs.PdfDocument(pdfurl, { width: 200, height: 200, title: "a pdf doc" })); + let addImageNode = action(() => Docs.ImageDocument(imgurl, { width: 200, title: "an image of a cat" })); + let addWebNode = action(() => Docs.WebDocument(weburl, { width: 200, height: 200, title: "a sample web page" })); + let addAudioNode = action(() => Docs.AudioDocument(audiourl, { width: 200, height: 200, title: "audio node" })); - let btns: [React.RefObject, IconName, string, () => Document][] = [ + let btns: [React.RefObject, IconName, string, () => Doc][] = [ [React.createRef(), "font", "Add Textbox", addTextNode], [React.createRef(), "image", "Add Image", addImageNode], [React.createRef(), "file-pdf", "Add PDF", addPDFNode], @@ -260,9 +261,8 @@ export class Main extends React.Component { let logoutRef = React.createRef(); let toggleWorkspaces = () => runInAction(() => this._workspacesShown = !this._workspacesShown); - let clearDatabase = action(() => Utils.Emit(Server.Socket, MessageStore.DeleteAll, {})); return [ - , + ,
@@ -271,7 +271,7 @@ export class Main extends React.Component {
,
-
+
]; } @@ -279,10 +279,10 @@ export class Main extends React.Component { get workspaceMenu() { let areWorkspacesShown = () => this._workspacesShown; let toggleWorkspaces = () => runInAction(() => this._workspacesShown = !this._workspacesShown); - let workspaces = CurrentUserUtils.UserDocument.GetT>(KeyStore.Workspaces, ListField); - return (!workspaces || workspaces === FieldWaiting || this.mainContainer === FieldWaiting) ? (null) : + let workspaces = Cast(CurrentUserUtils.UserDocument.workspaces, listSpec(Doc)); + return (!workspaces || !this.mainContainer) ? (null) : ; } @@ -303,17 +303,17 @@ export class Main extends React.Component { } // --------------- Northstar hooks ------------- / - private _northstarSchemas: Document[] = []; + private _northstarSchemas: Doc[] = []; @action SetNorthstarCatalog(ctlog: Catalog) { CurrentUserUtils.NorthstarDBCatalog = ctlog; if (ctlog && ctlog.schemas) { ctlog.schemas.map(schema => { - let schemaDocuments: Document[] = []; + let schemaDocuments: Doc[] = []; let attributesToBecomeDocs = CurrentUserUtils.GetAllNorthstarColumnAttributes(schema); Promise.all(attributesToBecomeDocs.reduce((promises, attr) => { - promises.push(Server.GetField(attr.displayName! + ".alias").then(action((field: Opt) => { - if (field instanceof Document) { + promises.push(DocServer.GetRefField(attr.displayName! + ".alias").then(action((field: Opt) => { + if (field instanceof Doc) { schemaDocuments.push(field); } else { var atmod = new ColumnAttributeModel(attr); @@ -321,12 +321,12 @@ export class Main extends React.Component { 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! }, undefined, attr.displayName! + ".alias")); + schemaDocuments.push(Docs.HistogramDocument(histoOp, { width: 200, height: 200, title: attr.displayName! })); } }))); return promises; }, [] as Promise[])).finally(() => - this._northstarSchemas.push(Documents.TreeDocument(schemaDocuments, { width: 50, height: 100, title: schema.displayName! }))); + this._northstarSchemas.push(Docs.TreeDocument(schemaDocuments, { width: 50, height: 100, title: schema.displayName! }))); }); } } @@ -338,7 +338,7 @@ export class Main extends React.Component { } (async () => { - await Documents.initProtos(); + await Docs.initProtos(); await CurrentUserUtils.loadCurrentUser(); ReactDOM.render(
, document.getElementById('root')); })(); diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 69401ceeb..2ff409b9b 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -6,13 +6,11 @@ import { observer } from "mobx-react"; import * as ReactDOM from 'react-dom'; import Measure from "react-measure"; import { Utils, returnTrue, emptyFunction, returnOne, returnZero } from "../../../Utils"; -import { Server } from "../../Server"; import { undoBatch, UndoManager } from "../../util/UndoManager"; import { DocumentView } from "../nodes/DocumentView"; import "./CollectionDockingView.scss"; import React = require("react"); import { SubCollectionViewProps } from "./CollectionSubView"; -import { ServerUtils } from "../../../server/ServerUtil"; import { DragManager, DragLinksAsDocuments } from "../../util/DragManager"; import { Transform } from '../../util/Transform'; import { Doc, Id, Opt, Field, FieldId } from "../../../new_fields/Doc"; @@ -206,7 +204,7 @@ export class CollectionDockingView extends React.Component) => + DocServer.GetRefField(docid).then(action(async (sourceDoc: Opt) => (sourceDoc instanceof Doc) && DragLinksAsDocuments(tab, x, y, sourceDoc))); } else if ((className === "lm_title" || className === "lm_tab lm_active") && !e.shiftKey) { @@ -216,7 +214,7 @@ export class CollectionDockingView extends React.Component) => { + DocServer.GetRefField(docid).then(action((f: Opt) => { if (f instanceof Doc) { DragManager.StartDocumentDrag([tab], new DragManager.DocumentDragData([f]), x, y, { @@ -301,7 +299,7 @@ export class CollectionDockingView extends React.Component { return FieldView.LayoutString(CollectionPDFView, fieldKey); } - private get curPage() { return this.props.Document.GetNumber(KeyStore.CurPage, -1); } - private get numPages() { return this.props.Document.GetNumber(KeyStore.NumPages, 0); } - @action onPageBack = () => this.curPage > 1 ? this.props.Document.SetNumber(KeyStore.CurPage, this.curPage - 1) : -1; - @action onPageForward = () => this.curPage < this.numPages ? this.props.Document.SetNumber(KeyStore.CurPage, this.curPage + 1) : -1; + private get curPage() { return NumCast(this.props.Document.curPage, -1); } + private get numPages() { return NumCast(this.props.Document.numPages); } + @action onPageBack = () => this.curPage > 1 ? (this.props.Document.curPage = this.curPage - 1) : -1; + @action onPageForward = () => this.curPage < this.numPages ? (this.props.Document.curPage = this.curPage + 1) : -1; private get uIButtons() { let scaling = Math.min(1.8, this.props.ScreenToLocalTransform().Scale); diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index 2e1175f28..874170f3d 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -5,7 +5,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, observable, untracked } from "mobx"; import { observer } from "mobx-react"; import ReactTable, { CellInfo, ComponentPropsGetterR, ReactTableDefaults } from "react-table"; -import { MAX_ROW_HEIGHT } from '../../views/globalCssVariables.scss' +import { MAX_ROW_HEIGHT } from '../../views/globalCssVariables.scss'; import "react-table/react-table.css"; import { emptyFunction, returnFalse, returnZero } from "../../../Utils"; import { SetupDrag } from "../../util/DragManager"; @@ -283,7 +283,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { // then by the time the options button is clicked, all of the fields should be in place. If a new field is added while this menu // is displayed (unlikely) it won't show up until something else changes. //TODO Types - untracked(() => docs.map(doc => Doc.GetAllPrototypes(doc).map(proto => proto._proxies.forEach((val: any, key: string) => keys[key] = false)))); + untracked(() => docs.map(doc => Doc.GetAllPrototypes(doc).map(proto => Object.keys(proto).forEach(key => keys[key] = false)))); this.columns.forEach(key => keys[key] = true); return Array.from(Object.keys(keys)).map(item => diff --git a/src/client/views/collections/CollectionVideoView.tsx b/src/client/views/collections/CollectionVideoView.tsx index 779dc8fc3..d314e3fc0 100644 --- a/src/client/views/collections/CollectionVideoView.tsx +++ b/src/client/views/collections/CollectionVideoView.tsx @@ -1,6 +1,5 @@ import { action, observable, trace } from "mobx"; import { observer } from "mobx-react"; -import { KeyStore } from "../../../fields/KeyStore"; import { ContextMenu } from "../ContextMenu"; import { CollectionViewType, CollectionBaseView, CollectionRenderProps } from "./CollectionBaseView"; import React = require("react"); @@ -8,6 +7,7 @@ import "./CollectionVideoView.scss"; import { CollectionFreeFormView } from "./collectionFreeForm/CollectionFreeFormView"; import { FieldView, FieldViewProps } from "../nodes/FieldView"; import { emptyFunction } from "../../../Utils"; +import { NumCast } from "../../../new_fields/Types"; @observer @@ -44,8 +44,9 @@ export class CollectionVideoView extends React.Component { if (ele) { this._player = ele.getElementsByTagName("video")[0]; console.log(this._player); - if (this.props.Document.GetNumber(KeyStore.CurPage, -1) >= 0) { - this._currentTimecode = this.props.Document.GetNumber(KeyStore.CurPage, -1); + const curPage = NumCast(this.props.Document.curPage, -1); + if (curPage >= 0) { + this._currentTimecode = curPage; } } } @@ -69,7 +70,7 @@ export class CollectionVideoView extends React.Component { (this._player as any).AHackBecauseSomethingResetsTheVideoToZero = -1; } else { this._currentTimecode = this._player.currentTime; - this.props.Document.SetNumber(KeyStore.CurPage, Math.round(this._currentTimecode)); + this.props.Document.curPage = Math.round(this._currentTimecode); } } } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx index 20c5a84bf..d4987fc18 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx @@ -1,15 +1,15 @@ import { observer } from "mobx-react"; -import { Document } from "../../../../fields/Document"; -import { KeyStore } from "../../../../fields/KeyStore"; import { Utils } from "../../../../Utils"; import "./CollectionFreeFormLinkView.scss"; import React = require("react"); import v5 = require("uuid/v5"); +import { StrCast, NumCast, BoolCast } from "../../../../new_fields/Types"; +import { Doc } from "../../../../new_fields/Doc"; export interface CollectionFreeFormLinkViewProps { - A: Document; - B: Document; - LinkDocs: Document[]; + A: Doc; + B: Doc; + LinkDocs: Doc[]; } @observer @@ -17,16 +17,16 @@ export class CollectionFreeFormLinkView extends React.Component { this.props.LinkDocs.map(l => - console.log("Link:" + l.Title)); + console.log("Link:" + StrCast(l.title))); } render() { let l = this.props.LinkDocs; let a = this.props.A; let b = this.props.B; - let x1 = a.GetNumber(KeyStore.X, 0) + (a.GetBoolean(KeyStore.IsMinimized, false) ? 5 : a.Width() / 2); - let y1 = a.GetNumber(KeyStore.Y, 0) + (a.GetBoolean(KeyStore.IsMinimized, false) ? 5 : a.Height() / 2); - let x2 = b.GetNumber(KeyStore.X, 0) + (b.GetBoolean(KeyStore.IsMinimized, false) ? 5 : b.Width() / 2); - let y2 = b.GetNumber(KeyStore.Y, 0) + (b.GetBoolean(KeyStore.IsMinimized, false) ? 5 : b.Height() / 2); + let x1 = NumCast(a.x) + (BoolCast(a.isMinimized, false) ? 5 : NumCast(a.width) / 2); + let y1 = NumCast(a.y) + (BoolCast(a.isMinimized, false) ? 5 : NumCast(a.height) / 2); + let x2 = NumCast(b.x) + (BoolCast(b.isMinimized, false) ? 5 : NumCast(b.width) / 2); + let y2 = NumCast(b.y) + (BoolCast(b.isMinimized, false) ? 5 : NumCast(b.height) / 2); return ( { _brushReactionDisposer?: IReactionDisposer; componentDidMount() { - this._brushReactionDisposer = reaction(() => this.props.Document.GetList(this.props.fieldKey, [] as Document[]).map(doc => doc.GetNumber(KeyStore.X, 0)), + this._brushReactionDisposer = reaction(() => Cast(this.props.Document[this.props.fieldKey], listSpec(Doc), []).map(doc => NumCast(doc.x)), () => { - let views = this.props.Document.GetList(this.props.fieldKey, [] as Document[]).filter(doc => doc.GetText(KeyStore.BackgroundLayout, "").indexOf("istogram") !== -1); + let views = Cast(this.props.Document[this.props.fieldKey], listSpec(Doc), []).filter(doc => StrCast(doc.backgroundLayout, "").indexOf("istogram") !== -1); for (let i = 0; i < views.length; i++) { for (let j = 0; j < views.length; j++) { let srcDoc = views[j]; let dstDoc = views[i]; - let x1 = srcDoc.GetNumber(KeyStore.X, 0); - let x1w = srcDoc.GetNumber(KeyStore.Width, -1); - let x2 = dstDoc.GetNumber(KeyStore.X, 0); - let x2w = dstDoc.GetNumber(KeyStore.Width, -1); + let x1 = NumCast(srcDoc.x); + let x1w = NumCast(srcDoc.width, -1); + let x2 = NumCast(dstDoc.x); + let x2w = NumCast(dstDoc.width, -1); if (x1w < 0 || x2w < 0 || i === j) { continue; } let dstTarg = dstDoc; let srcTarg = srcDoc; - let findBrush = (field: ListField) => field.Data.findIndex(brush => { - let bdocs = brush ? brush.GetList(KeyStore.BrushingDocs, [] as Document[]) : []; + let findBrush = (field: List) => field.findIndex(brush => { + let bdocs = brush ? Cast(brush.brushingDocs, listSpec(Doc), []) : []; return (bdocs.length && ((bdocs[0] === dstTarg && bdocs[1] === srcTarg)) ? true : false); }); - let brushAction = (field: ListField) => { + let brushAction = (field: List) => { let found = findBrush(field); if (found !== -1) { console.log("REMOVE BRUSH " + srcTarg.Title + " " + dstTarg.Title); - field.Data.splice(found, 1); + field.splice(found, 1); } }; if (Math.abs(x1 + x1w - x2) < 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); + let linkDoc: Doc = new Doc(); + linkDoc.title = "Histogram Brush"; + linkDoc.linkDescription = "Brush between " + StrCast(srcTarg.title) + " and " + StrCast(dstTarg.Title); + linkDoc.brushingDocs = new List([dstTarg, srcTarg]); - brushAction = (field: ListField) => { + brushAction = (field: List) => { if (findBrush(field) === -1) { console.log("ADD BRUSH " + srcTarg.Title + " " + dstTarg.Title); - (findBrush(field) === -1) && field.Data.push(linkDoc); + (findBrush(field) === -1) && field.push(linkDoc); } }; } - dstTarg.GetOrCreateAsync(KeyStore.BrushingDocs, ListField, brushAction); - srcTarg.GetOrCreateAsync(KeyStore.BrushingDocs, ListField, brushAction); + let dstBrushDocs = Cast(dstTarg.brushingDocs, listSpec(Doc)); + if (dstBrushDocs === undefined) { + dstTarg.brushingDocs = dstBrushDocs = new List(); + } + let srcBrushDocs = Cast(srcTarg.brushingDocs, listSpec(Doc)); + if (srcBrushDocs === undefined) { + srcTarg.brushingDocs = srcBrushDocs = new List(); + } + brushAction(dstBrushDocs); + brushAction(srcBrushDocs); } } @@ -70,9 +79,9 @@ export class CollectionFreeFormLinksView extends React.Component sv.props.ContainingCollectionView && sv.props.ContainingCollectionView.props.Document === this.props.Document); } @@ -82,12 +91,12 @@ export class CollectionFreeFormLinksView extends React.Component { let srcViews = this.documentAnchors(connection.a); let targetViews = this.documentAnchors(connection.b); - let possiblePairs: { a: Document, b: Document, }[] = []; + let possiblePairs: { a: Doc, b: Doc, }[] = []; srcViews.map(sv => targetViews.map(tv => possiblePairs.push({ a: sv.props.Document, b: tv.props.Document }))); possiblePairs.map(possiblePair => drawnPairs.reduce((found, drawnPair) => { let match = (possiblePair.a === drawnPair.a && possiblePair.b === drawnPair.b); - if (match && !drawnPair.l.reduce((found, link) => found || link.Id === connection.l.Id, false)) { + if (match && !drawnPair.l.reduce((found, link) => found || link[Id] === connection.l[Id], false)) { drawnPair.l.push(connection.l); } return match || found; @@ -96,7 +105,7 @@ export class CollectionFreeFormLinksView extends React.Component ); } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx index cf0a6de00..036745eca 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx @@ -1,6 +1,5 @@ import { computed } from "mobx"; import { observer } from "mobx-react"; -import { KeyStore } from "../../../../fields/KeyStore"; import { CollectionViewProps, CursorEntry } from "../CollectionSubView"; import "./CollectionFreeFormView.scss"; import React = require("react"); diff --git a/src/client/views/nodes/IconBox.tsx b/src/client/views/nodes/IconBox.tsx index 9c90c0a0e..f7cceb3d4 100644 --- a/src/client/views/nodes/IconBox.tsx +++ b/src/client/views/nodes/IconBox.tsx @@ -4,12 +4,12 @@ import { faCaretUp, faFilePdf, faFilm, faImage, faObjectGroup, faStickyNote } fr import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { action, computed } from "mobx"; import { observer } from "mobx-react"; -import { Document } from '../../../fields/Document'; -import { IconField } from "../../../fields/IconFIeld"; -import { KeyStore } from "../../../fields/KeyStore"; import { SelectionManager } from "../../util/SelectionManager"; import { FieldView, FieldViewProps } from './FieldView'; import "./IconBox.scss"; +import { Cast } from "../../../new_fields/Types"; +import { Doc } from "../../../new_fields/Doc"; +import { IconField } from "../../../new_fields/IconField"; library.add(faCaretUp); @@ -22,8 +22,8 @@ library.add(faFilm); export class IconBox extends React.Component { public static LayoutString() { return FieldView.LayoutString(IconBox); } - @computed get maximized() { return this.props.Document.GetT(KeyStore.MaximizedDoc, Document); } - @computed get layout(): string { return this.props.Document.GetData(this.props.fieldKey, IconField, "

Error loading layout data

" as string); } + @computed get maximized() { return Cast(this.props.Document.maximizedDoc, Doc); } + @computed get layout(): string { const field = Cast(this.props.Document[this.props.fieldKey], IconField); return field ? field.layout : "

Error loading layout data

"; } @computed get minimizedIcon() { return IconBox.DocumentIcon(this.layout); } public static DocumentIcon(layout: string) { @@ -33,7 +33,7 @@ export class IconBox extends React.Component { layout.indexOf("Video") !== -1 ? faFilm : layout.indexOf("Collection") !== -1 ? faObjectGroup : faCaretUp; - return + return ; } render() { -- cgit v1.2.3-70-g09d2 From d4a77dd055685dd81a762ef40e0c3b7606586e9c Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Sat, 27 Apr 2019 21:40:17 -0400 Subject: Split more files up --- src/client/DocServer.ts | 3 +- src/client/northstar/dash-fields/HistogramField.ts | 2 +- src/client/northstar/dash-nodes/HistogramBox.tsx | 3 +- src/client/util/Scripting.ts | 1 + src/client/views/Main.tsx | 3 +- .../views/collections/CollectionBaseView.tsx | 3 +- .../views/collections/CollectionDockingView.tsx | 3 +- .../views/collections/CollectionSchemaView.tsx | 3 +- src/client/views/collections/CollectionSubView.tsx | 3 +- .../views/collections/CollectionTreeView.tsx | 3 +- .../CollectionFreeFormLinksView.tsx | 3 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 3 +- src/client/views/nodes/DocumentView.tsx | 3 +- src/client/views/nodes/FieldView.tsx | 1 + src/client/views/nodes/LinkMenu.tsx | 3 +- src/new_fields/Doc.ts | 37 +++------------------- src/new_fields/HtmlField.ts | 2 +- src/new_fields/IconField.ts | 2 +- src/new_fields/InkField.ts | 2 +- src/new_fields/List.ts | 3 +- src/new_fields/ObjectField.ts | 17 ++++++++++ src/new_fields/Proxy.ts | 4 ++- src/new_fields/RefField.ts | 18 +++++++++++ src/new_fields/RichTextField.ts | 2 +- src/new_fields/Schema.ts | 8 ++--- src/new_fields/Types.ts | 2 +- src/new_fields/URLField.ts | 2 +- src/new_fields/util.ts | 4 ++- .../authentication/controllers/WorkspacesMenu.tsx | 3 +- src/server/database.ts | 2 ++ 30 files changed, 88 insertions(+), 60 deletions(-) create mode 100644 src/new_fields/ObjectField.ts create mode 100644 src/new_fields/RefField.ts (limited to 'src/client/northstar') diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts index 3f17baec6..c7cbfce37 100644 --- a/src/client/DocServer.ts +++ b/src/client/DocServer.ts @@ -1,8 +1,9 @@ import * as OpenSocket from 'socket.io-client'; import { MessageStore, Types, Message } from "./../server/Message"; -import { Opt, FieldWaiting, RefField, HandleUpdate } from '../new_fields/Doc'; +import { Opt, FieldWaiting } from '../new_fields/Doc'; import { Utils } from '../Utils'; import { SerializationHelper } from './util/SerializationHelper'; +import { RefField, HandleUpdate } from '../new_fields/RefField'; export namespace DocServer { const _cache: { [id: string]: RefField | Promise> } = {}; diff --git a/src/client/northstar/dash-fields/HistogramField.ts b/src/client/northstar/dash-fields/HistogramField.ts index 118f4cf7f..730289536 100644 --- a/src/client/northstar/dash-fields/HistogramField.ts +++ b/src/client/northstar/dash-fields/HistogramField.ts @@ -3,7 +3,7 @@ import { custom, serializable } from "serializr"; import { ColumnAttributeModel } from "../../../client/northstar/core/attribute/AttributeModel"; import { AttributeTransformationModel } from "../../../client/northstar/core/attribute/AttributeTransformationModel"; import { HistogramOperation } from "../../../client/northstar/operations/HistogramOperation"; -import { ObjectField } from "../../../new_fields/Doc"; +import { ObjectField } from "../../../new_fields/ObjectField"; import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils"; import { OmitKeys } from "../../../Utils"; import { Deserializable } from "../../util/SerializationHelper"; diff --git a/src/client/northstar/dash-nodes/HistogramBox.tsx b/src/client/northstar/dash-nodes/HistogramBox.tsx index 4a65b14cf..a9c68ccba 100644 --- a/src/client/northstar/dash-nodes/HistogramBox.tsx +++ b/src/client/northstar/dash-nodes/HistogramBox.tsx @@ -20,7 +20,8 @@ import { HistogramLabelPrimitives } from "./HistogramLabelPrimitives"; import { StyleConstants } from "../utils/StyleContants"; import { NumCast, Cast } from "../../../new_fields/Types"; import { listSpec } from "../../../new_fields/Schema"; -import { Doc, Id } from "../../../new_fields/Doc"; +import { Doc } from "../../../new_fields/Doc"; +import { Id } from "../../../new_fields/RefField"; @observer diff --git a/src/client/util/Scripting.ts b/src/client/util/Scripting.ts index dbec82340..e45f61c11 100644 --- a/src/client/util/Scripting.ts +++ b/src/client/util/Scripting.ts @@ -11,6 +11,7 @@ import { Docs } from "../documents/Documents"; import { Doc, Field } from '../../new_fields/Doc'; import { ImageField, PdfField, VideoField, AudioField } from '../../new_fields/URLField'; import { List } from '../../new_fields/List'; +import { RichTextField } from '../../new_fields/RichTextField'; export interface ScriptSucccess { success: true; diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index 1e3d4e259..4a68d1c68 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -33,10 +33,11 @@ import { MainOverlayTextBox } from './MainOverlayTextBox'; import { DocumentView } from './nodes/DocumentView'; import { PreviewCursor } from './PreviewCursor'; import { SelectionManager } from '../util/SelectionManager'; -import { FieldResult, Field, Doc, Id, Opt } from '../../new_fields/Doc'; +import { FieldResult, Field, Doc, Opt } from '../../new_fields/Doc'; import { Cast, FieldValue, StrCast } from '../../new_fields/Types'; import { DocServer } from '../DocServer'; import { listSpec } from '../../new_fields/Schema'; +import { Id } from '../../new_fields/RefField'; @observer diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx index 4807dc40a..b2fba1415 100644 --- a/src/client/views/collections/CollectionBaseView.tsx +++ b/src/client/views/collections/CollectionBaseView.tsx @@ -4,9 +4,10 @@ import * as React from 'react'; import { ContextMenu } from '../ContextMenu'; import { FieldViewProps } from '../nodes/FieldView'; import { Cast, FieldValue, PromiseValue, NumCast } from '../../../new_fields/Types'; -import { Doc, FieldResult, Opt, Id } from '../../../new_fields/Doc'; +import { Doc, FieldResult, Opt } from '../../../new_fields/Doc'; import { listSpec } from '../../../new_fields/Schema'; import { List } from '../../../new_fields/List'; +import { Id } from '../../../new_fields/RefField'; export enum CollectionViewType { Invalid, diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 2ff409b9b..1574562c6 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -13,11 +13,12 @@ import React = require("react"); import { SubCollectionViewProps } from "./CollectionSubView"; import { DragManager, DragLinksAsDocuments } from "../../util/DragManager"; import { Transform } from '../../util/Transform'; -import { Doc, Id, Opt, Field, FieldId } from "../../../new_fields/Doc"; +import { Doc, Opt, Field } from "../../../new_fields/Doc"; import { Cast, NumCast } from "../../../new_fields/Types"; import { List } from "../../../new_fields/List"; import { DocServer } from "../../DocServer"; import { listSpec } from "../../../new_fields/Schema"; +import { Id, FieldId } from "../../../new_fields/RefField"; @observer export class CollectionDockingView extends React.Component { diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index 874170f3d..58d20819b 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -19,10 +19,11 @@ import { DocumentView } from "../nodes/DocumentView"; import { FieldView, FieldViewProps } from "../nodes/FieldView"; import "./CollectionSchemaView.scss"; import { CollectionSubView } from "./CollectionSubView"; -import { Opt, Field, Doc, Id } from "../../../new_fields/Doc"; +import { Opt, Field, Doc } from "../../../new_fields/Doc"; import { Cast, FieldValue, NumCast } from "../../../new_fields/Types"; import { listSpec } from "../../../new_fields/Schema"; import { List } from "../../../new_fields/List"; +import { Id } from "../../../new_fields/RefField"; // bcz: need to add drag and drop of rows and columns. This seems like it might work for rows: https://codesandbox.io/s/l94mn1q657 diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 558a8728f..4d090b680 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -10,12 +10,13 @@ import * as rp from 'request-promise'; import { CollectionView } from "./CollectionView"; import { CollectionPDFView } from "./CollectionPDFView"; import { CollectionVideoView } from "./CollectionVideoView"; -import { Doc, ObjectField, Opt } from "../../../new_fields/Doc"; +import { Doc, Opt } from "../../../new_fields/Doc"; import { DocComponent } from "../DocComponent"; import { listSpec } from "../../../new_fields/Schema"; import { Cast, PromiseValue } from "../../../new_fields/Types"; import { List } from "../../../new_fields/List"; import { DocServer } from "../../DocServer"; +import { ObjectField } from "../../../new_fields/ObjectField"; export interface CollectionViewProps extends FieldViewProps { addDocument: (document: Doc, allowDuplicates?: boolean) => boolean; diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index c9d8d83c8..7ec9a8549 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -10,7 +10,8 @@ import "./CollectionTreeView.scss"; import React = require("react"); import { Document, listSpec } from '../../../new_fields/Schema'; import { Cast, StrCast, BoolCast } from '../../../new_fields/Types'; -import { Doc, Id } from '../../../new_fields/Doc'; +import { Doc } from '../../../new_fields/Doc'; +import { Id } from '../../../new_fields/RefField'; export interface TreeViewProps { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx index ce9995630..f693d55e8 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx @@ -7,10 +7,11 @@ import { CollectionViewProps } from "../CollectionSubView"; import "./CollectionFreeFormLinksView.scss"; import { CollectionFreeFormLinkView } from "./CollectionFreeFormLinkView"; import React = require("react"); -import { Doc, Id } from "../../../../new_fields/Doc"; +import { Doc } from "../../../../new_fields/Doc"; import { Cast, FieldValue, NumCast, StrCast } from "../../../../new_fields/Types"; import { listSpec } from "../../../../new_fields/Schema"; import { List } from "../../../../new_fields/List"; +import { Id } from "../../../../new_fields/RefField"; @observer export class CollectionFreeFormLinksView extends React.Component { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 047fbad18..18107e98a 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -19,10 +19,11 @@ import { MarqueeView } from "./MarqueeView"; import React = require("react"); import v5 = require("uuid/v5"); import { createSchema, makeInterface, listSpec } from "../../../../new_fields/Schema"; -import { Doc, Id } from "../../../../new_fields/Doc"; +import { Doc } from "../../../../new_fields/Doc"; import { FieldValue, Cast, NumCast } from "../../../../new_fields/Types"; import { pageSchema } from "../../nodes/ImageBox"; import { List } from "../../../../new_fields/List"; +import { Id } from "../../../../new_fields/RefField"; export const panZoomSchema = createSchema({ panX: "number", diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index aabc1633e..c304b6a35 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -15,7 +15,7 @@ import { ContextMenu } from "../ContextMenu"; import { DocumentContentsView } from "./DocumentContentsView"; import "./DocumentView.scss"; import React = require("react"); -import { Field, Opt, Doc, Id } from "../../../new_fields/Doc"; +import { Opt, Doc } from "../../../new_fields/Doc"; import { DocComponent } from "../DocComponent"; import { createSchema, makeInterface, listSpec } from "../../../new_fields/Schema"; import { FieldValue, Cast, PromiseValue } from "../../../new_fields/Types"; @@ -24,6 +24,7 @@ import { CollectionFreeFormView } from "../collections/collectionFreeForm/Collec import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils"; import { MarqueeView } from "../collections/collectionFreeForm/MarqueeView"; import { DocServer } from "../../DocServer"; +import { Id } from "../../../new_fields/RefField"; const linkSchema = createSchema({ title: "string", diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index c00c47fc4..dc36c5914 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -16,6 +16,7 @@ import { Opt, Doc, FieldResult } from "../../../new_fields/Doc"; import { List } from "../../../new_fields/List"; import { ImageField, VideoField, AudioField } from "../../../new_fields/URLField"; import { IconField } from "../../../new_fields/IconField"; +import { RichTextField } from "../../../new_fields/RichTextField"; // diff --git a/src/client/views/nodes/LinkMenu.tsx b/src/client/views/nodes/LinkMenu.tsx index 3ecc8555d..e21adebbc 100644 --- a/src/client/views/nodes/LinkMenu.tsx +++ b/src/client/views/nodes/LinkMenu.tsx @@ -5,9 +5,10 @@ import { LinkBox } from "./LinkBox"; import { LinkEditor } from "./LinkEditor"; import './LinkMenu.scss'; import React = require("react"); -import { Doc, Id } from "../../../new_fields/Doc"; +import { Doc } from "../../../new_fields/Doc"; import { Cast, FieldValue } from "../../../new_fields/Types"; import { listSpec } from "../../../new_fields/Schema"; +import { Id } from "../../../new_fields/RefField"; interface Props { docView: DocumentView; diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index fb7b6e360..4ef2a465f 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -8,38 +8,8 @@ import { Cast, ToConstructor, PromiseValue, FieldValue } from "./Types"; import { UndoManager, undoBatch } from "../client/util/UndoManager"; import { listSpec } from "./Schema"; import { List } from "./List"; - -export type FieldId = string; -export const HandleUpdate = Symbol("HandleUpdate"); -export const Id = Symbol("Id"); -export abstract class RefField { - @serializable(alias("id", primitive())) - private __id: FieldId; - readonly [Id]: FieldId; - - constructor(id?: FieldId) { - this.__id = id || Utils.GenerateGuid(); - this[Id] = this.__id; - } - - protected [HandleUpdate]?(diff: any): void; -} - -export const Update = Symbol("Update"); -export const OnUpdate = Symbol("OnUpdate"); -export const Parent = Symbol("Parent"); -export class ObjectField { - protected [OnUpdate]?: (diff?: any) => void; - private [Parent]?: Doc; - readonly [Id] = ""; -} - -export namespace ObjectField { - export function MakeCopy(field: ObjectField) { - //TODO Types - return field; - } -} +import { ObjectField } from "./ObjectField"; +import { RefField, FieldId, Id } from "./RefField"; export function IsField(field: any): field is Field { return (typeof field === "string") @@ -53,6 +23,7 @@ export type Opt = T | undefined; export type FieldWaiting = T extends undefined ? never : Promise; export type FieldResult = Opt | FieldWaiting>; +export const Update = Symbol("Update"); export const Self = Symbol("Self"); @Deserializable("doc").withFields(["id"]) @@ -161,7 +132,7 @@ export namespace Doc { copy[key] = field; } } - }) + }); return copy; } diff --git a/src/new_fields/HtmlField.ts b/src/new_fields/HtmlField.ts index 76fdb1f62..808a3499b 100644 --- a/src/new_fields/HtmlField.ts +++ b/src/new_fields/HtmlField.ts @@ -1,6 +1,6 @@ import { Deserializable } from "../client/util/SerializationHelper"; import { serializable, primitive } from "serializr"; -import { ObjectField } from "./Doc"; +import { ObjectField } from "./ObjectField"; @Deserializable("html") export class HtmlField extends ObjectField { diff --git a/src/new_fields/IconField.ts b/src/new_fields/IconField.ts index 32f3aa4d5..46f111f8e 100644 --- a/src/new_fields/IconField.ts +++ b/src/new_fields/IconField.ts @@ -1,6 +1,6 @@ import { Deserializable } from "../client/util/SerializationHelper"; import { serializable, primitive } from "serializr"; -import { ObjectField } from "./Doc"; +import { ObjectField } from "./ObjectField"; @Deserializable("icon") export class IconField extends ObjectField { diff --git a/src/new_fields/InkField.ts b/src/new_fields/InkField.ts index 49e6bf61e..42223c494 100644 --- a/src/new_fields/InkField.ts +++ b/src/new_fields/InkField.ts @@ -1,6 +1,6 @@ import { Deserializable } from "../client/util/SerializationHelper"; import { serializable, custom, createSimpleSchema, list, object, map } from "serializr"; -import { ObjectField } from "./Doc"; +import { ObjectField } from "./ObjectField"; export enum InkTool { None, diff --git a/src/new_fields/List.ts b/src/new_fields/List.ts index f01ac210a..428f661c9 100644 --- a/src/new_fields/List.ts +++ b/src/new_fields/List.ts @@ -1,8 +1,9 @@ import { Deserializable, autoObject } from "../client/util/SerializationHelper"; -import { Field, ObjectField, Update, OnUpdate, Self } from "./Doc"; +import { Field, Update, Self } from "./Doc"; import { setter, getter } from "./util"; import { serializable, alias, list } from "serializr"; import { observable } from "mobx"; +import { ObjectField, OnUpdate } from "./ObjectField"; @Deserializable("list") class ListImpl extends ObjectField { diff --git a/src/new_fields/ObjectField.ts b/src/new_fields/ObjectField.ts new file mode 100644 index 000000000..9cac2c528 --- /dev/null +++ b/src/new_fields/ObjectField.ts @@ -0,0 +1,17 @@ +import { Doc } from "./Doc"; + +export const OnUpdate = Symbol("OnUpdate"); +export const Parent = Symbol("Parent"); +const Id = Symbol("Object Id"); +export class ObjectField { + protected [OnUpdate]?: (diff?: any) => void; + private [Parent]?: Doc; + readonly [Id] = ""; +} + +export namespace ObjectField { + export function MakeCopy(field: ObjectField) { + //TODO Types + return field; + } +} diff --git a/src/new_fields/Proxy.ts b/src/new_fields/Proxy.ts index 2aa78731e..56e41cc0f 100644 --- a/src/new_fields/Proxy.ts +++ b/src/new_fields/Proxy.ts @@ -1,8 +1,10 @@ import { Deserializable } from "../client/util/SerializationHelper"; -import { RefField, Id, ObjectField, FieldWaiting } from "./Doc"; +import { FieldWaiting } from "./Doc"; import { primitive, serializable } from "serializr"; import { observable, action } from "mobx"; import { DocServer } from "../client/DocServer"; +import { RefField, Id } from "./RefField"; +import { ObjectField } from "./ObjectField"; @Deserializable("proxy") export class ProxyField extends ObjectField { diff --git a/src/new_fields/RefField.ts b/src/new_fields/RefField.ts new file mode 100644 index 000000000..202c65f21 --- /dev/null +++ b/src/new_fields/RefField.ts @@ -0,0 +1,18 @@ +import { serializable, primitive, alias } from "serializr"; +import { Utils } from "../Utils"; + +export type FieldId = string; +export const HandleUpdate = Symbol("HandleUpdate"); +export const Id = Symbol("Id"); +export abstract class RefField { + @serializable(alias("id", primitive())) + private __id: FieldId; + readonly [Id]: FieldId; + + constructor(id?: FieldId) { + this.__id = id || Utils.GenerateGuid(); + this[Id] = this.__id; + } + + protected [HandleUpdate]?(diff: any): void; +} diff --git a/src/new_fields/RichTextField.ts b/src/new_fields/RichTextField.ts index 156e4efd9..0fa3cf73c 100644 --- a/src/new_fields/RichTextField.ts +++ b/src/new_fields/RichTextField.ts @@ -1,4 +1,4 @@ -import { ObjectField } from "./Doc"; +import { ObjectField } from "./ObjectField"; import { serializable } from "serializr"; export class RichTextField extends ObjectField { diff --git a/src/new_fields/Schema.ts b/src/new_fields/Schema.ts index 5081521c7..7444878fe 100644 --- a/src/new_fields/Schema.ts +++ b/src/new_fields/Schema.ts @@ -21,15 +21,15 @@ export function makeInterface(...schemas: T): (doc?: Doc) } } const proto = new Proxy({}, { - get(target: any, prop) { - const field = target.doc[prop]; + get(target: any, prop, receiver) { + const field = receiver.doc[prop]; if (prop in schema) { return Cast(field, (schema as any)[prop]); } return field; }, - set(target: any, prop, value) { - target.doc[prop] = value; + set(target: any, prop, value, receiver) { + receiver.doc[prop] = value; return true; } }); diff --git a/src/new_fields/Types.ts b/src/new_fields/Types.ts index 7fa18673f..3f8eabd45 100644 --- a/src/new_fields/Types.ts +++ b/src/new_fields/Types.ts @@ -1,4 +1,4 @@ -import { Field, Opt, FieldWaiting, FieldResult, RefField } from "./Doc"; +import { Field, Opt, FieldResult } from "./Doc"; import { List } from "./List"; export type ToType | ListSpec> = diff --git a/src/new_fields/URLField.ts b/src/new_fields/URLField.ts index 1da245e73..95c679df7 100644 --- a/src/new_fields/URLField.ts +++ b/src/new_fields/URLField.ts @@ -1,6 +1,6 @@ import { Deserializable } from "../client/util/SerializationHelper"; import { serializable, custom } from "serializr"; -import { ObjectField } from "./Doc"; +import { ObjectField } from "./ObjectField"; function url() { return custom( diff --git a/src/new_fields/util.ts b/src/new_fields/util.ts index 2d9721b2e..011e8c8d9 100644 --- a/src/new_fields/util.ts +++ b/src/new_fields/util.ts @@ -1,8 +1,10 @@ import { UndoManager } from "../client/util/UndoManager"; -import { Update, OnUpdate, Parent, ObjectField, RefField, Doc, Id, Field } from "./Doc"; +import { Update, Doc, Field } from "./Doc"; import { SerializationHelper } from "../client/util/SerializationHelper"; import { ProxyField } from "./Proxy"; import { FieldValue } from "./Types"; +import { RefField, Id } from "./RefField"; +import { ObjectField, Parent, OnUpdate } from "./ObjectField"; export function setter(target: any, prop: string | symbol | number, value: any, receiver: any): boolean { if (SerializationHelper.IsSerializing()) { diff --git a/src/server/authentication/controllers/WorkspacesMenu.tsx b/src/server/authentication/controllers/WorkspacesMenu.tsx index 29327e5ad..91756315d 100644 --- a/src/server/authentication/controllers/WorkspacesMenu.tsx +++ b/src/server/authentication/controllers/WorkspacesMenu.tsx @@ -3,8 +3,9 @@ import { observable, action, configure, reaction, computed, ObservableMap, runIn import { observer } from "mobx-react"; import './WorkspacesMenu.css'; import { EditableView } from '../../../client/views/EditableView'; -import { Doc, Id } from '../../../new_fields/Doc'; +import { Doc } from '../../../new_fields/Doc'; import { StrCast } from '../../../new_fields/Types'; +import { Id } from '../../../new_fields/RefField'; export interface WorkspaceMenuProps { active: Doc | undefined; diff --git a/src/server/database.ts b/src/server/database.ts index a61b4d823..6b3b6797f 100644 --- a/src/server/database.ts +++ b/src/server/database.ts @@ -60,11 +60,13 @@ export class Database { } public getDocument(id: string, fn: (result?: Transferable) => void, collectionName = Database.DocumentsCollection) { + console.log("getDocument"); this.db && this.db.collection(collectionName).findOne({ id: id }, (err, result) => fn(result ? ({ id: result._id, type: result.type, data: result.data }) : undefined)); } public getDocuments(ids: string[], fn: (result: Transferable[]) => void, collectionName = Database.DocumentsCollection) { + console.log("getDocuments"); this.db && this.db.collection(collectionName).find({ id: { "$in": ids } }).toArray((err, docs) => { if (err) { console.log(err.message); -- cgit v1.2.3-70-g09d2 From 506af03831bf3cc002f93ad8708eafb909c0a194 Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Sat, 27 Apr 2019 22:27:26 -0400 Subject: Various fixes --- src/client/DocServer.ts | 24 ++++++++++++++++++---- src/client/documents/Documents.ts | 2 +- src/client/northstar/dash-nodes/HistogramBox.tsx | 2 +- src/client/views/collections/CollectionPDFView.tsx | 2 +- src/client/views/collections/CollectionSubView.tsx | 1 + .../views/collections/CollectionVideoView.tsx | 2 +- src/client/views/collections/CollectionView.tsx | 2 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 2 +- src/client/views/nodes/FieldView.tsx | 4 ++-- src/client/views/nodes/FormattedTextBox.tsx | 2 +- src/client/views/nodes/KeyValueBox.tsx | 2 +- src/new_fields/util.ts | 5 +++-- src/server/database.ts | 21 +++++++++++++------ src/server/index.ts | 10 +++++---- 14 files changed, 55 insertions(+), 26 deletions(-) (limited to 'src/client/northstar') diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts index c7cbfce37..07997f072 100644 --- a/src/client/DocServer.ts +++ b/src/client/DocServer.ts @@ -55,12 +55,28 @@ export namespace DocServer { map[id] = cached; } } - const prom = Utils.EmitCallback(_socket, MessageStore.GetFields, requestedIds); - requestedIds.map((id, index) => _cache[id] = prom.then((fields: RefField[]) => fields[index])); + const prom = Utils.EmitCallback(_socket, MessageStore.GetRefFields, requestedIds).then(fields => { + for (const key in fields) { + const field = fields[key]; + if (field) { + fields[key] = SerializationHelper.Deserialize(field); + } + } + return fields; + }); + requestedIds.forEach((id, index) => _cache[id] = prom.then((fields: RefField[]) => fields[index])); const fields = await prom; - requestedIds.map((id, index) => map[id] = fields[index]); + requestedIds.forEach((id, index) => { + const field = fields[index]; + if (field) { + _cache[id] = field; + } else { + delete _cache[id]; + } + map[id] = field; + }); const otherFields = await Promise.all(promises); - waitingIds.map((id, index) => map[id] = otherFields[index]); + waitingIds.forEach((id, index) => map[id] = otherFields[index]); return map; } diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index c30fb21d5..2a9687bda 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -138,7 +138,7 @@ export namespace Docs { return webProto; } function CreateCollectionPrototype(): Doc { - let collProto = setupPrototypeOptions(collProtoId, "COLLECTION_PROTO", CollectionView.LayoutString("DataKey"), + let collProto = setupPrototypeOptions(collProtoId, "COLLECTION_PROTO", CollectionView.LayoutString("data"), { panX: 0, panY: 0, scale: 1, width: 500, height: 500 }); return collProto; } diff --git a/src/client/northstar/dash-nodes/HistogramBox.tsx b/src/client/northstar/dash-nodes/HistogramBox.tsx index a9c68ccba..19d108676 100644 --- a/src/client/northstar/dash-nodes/HistogramBox.tsx +++ b/src/client/northstar/dash-nodes/HistogramBox.tsx @@ -26,7 +26,7 @@ import { Id } from "../../../new_fields/RefField"; @observer export class HistogramBox extends React.Component { - public static LayoutString(fieldStr: string = "DataKey") { return FieldView.LayoutString(HistogramBox, fieldStr); } + public static LayoutString(fieldStr: string = "data") { return FieldView.LayoutString(HistogramBox, fieldStr); } private _dropXRef = React.createRef(); private _dropYRef = React.createRef(); private _dropXDisposer?: DragManager.DragDropDisposer; diff --git a/src/client/views/collections/CollectionPDFView.tsx b/src/client/views/collections/CollectionPDFView.tsx index e73b7b4a6..99438b4e8 100644 --- a/src/client/views/collections/CollectionPDFView.tsx +++ b/src/client/views/collections/CollectionPDFView.tsx @@ -13,7 +13,7 @@ import { NumCast } from "../../../new_fields/Types"; @observer export class CollectionPDFView extends React.Component { - public static LayoutString(fieldKey: string = "DataKey") { + public static LayoutString(fieldKey: string = "data") { return FieldView.LayoutString(CollectionPDFView, fieldKey); } diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 4d090b680..2c2d74302 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -53,6 +53,7 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T) { @action protected async setCursorPosition(position: [number, number]) { + return; let ind; let doc = this.props.Document; let id = CurrentUserUtils.id; diff --git a/src/client/views/collections/CollectionVideoView.tsx b/src/client/views/collections/CollectionVideoView.tsx index d314e3fc0..d45be228a 100644 --- a/src/client/views/collections/CollectionVideoView.tsx +++ b/src/client/views/collections/CollectionVideoView.tsx @@ -18,7 +18,7 @@ export class CollectionVideoView extends React.Component { @observable _currentTimecode: number = 0; @observable _isPlaying: boolean = false; - public static LayoutString(fieldKey: string = "DataKey") { + public static LayoutString(fieldKey: string = "data") { return FieldView.LayoutString(CollectionVideoView, fieldKey); } private get uIButtons() { diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index e7bf1e121..b72065bca 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -13,7 +13,7 @@ import { trace } from 'mobx'; @observer export class CollectionView extends React.Component { - public static LayoutString(fieldStr: string = "DataKey") { return FieldView.LayoutString(CollectionView, fieldStr); } + public static LayoutString(fieldStr: string = "data") { return FieldView.LayoutString(CollectionView, fieldStr); } private SubView = (type: CollectionViewType, renderProps: CollectionRenderProps) => { let props = { ...this.props, ...renderProps }; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 18107e98a..dfacca204 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -314,7 +314,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { {this.childViews} - + {/* */} diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index dc36c5914..df76f7cea 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -45,8 +45,8 @@ export interface FieldViewProps { @observer export class FieldView extends React.Component { - public static LayoutString(fieldType: { name: string }, fieldStr: string = "DataKey") { - return `<${fieldType.name} {...props} fieldKey={${fieldStr}} />`; + public static LayoutString(fieldType: { name: string }, fieldStr: string = "data") { + return `<${fieldType.name} {...props} fieldKey={"${fieldStr}"} />`; } @computed diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 7a85c9dd3..96512718f 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -55,7 +55,7 @@ const RichTextDocument = makeInterface(richTextSchema); @observer export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTextBoxOverlay), RichTextDocument>(RichTextDocument) { - public static LayoutString(fieldStr: string = "DataKey") { + public static LayoutString(fieldStr: string = "data") { return FieldView.LayoutString(FormattedTextBox, fieldStr); } private _ref: React.RefObject; diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx index ae39ebe2d..876a3c173 100644 --- a/src/client/views/nodes/KeyValueBox.tsx +++ b/src/client/views/nodes/KeyValueBox.tsx @@ -14,7 +14,7 @@ import { Doc, IsField } from "../../../new_fields/Doc"; export class KeyValueBox extends React.Component { private _mainCont = React.createRef(); - public static LayoutString(fieldStr: string = "DataKey") { return FieldView.LayoutString(KeyValueBox, fieldStr); } + public static LayoutString(fieldStr: string = "data") { return FieldView.LayoutString(KeyValueBox, fieldStr); } @observable private _keyInput: string = ""; @observable private _valueInput: string = ""; @computed get splitPercentage() { return NumCast(this.props.Document.schemaSplitPercentage, 50); } diff --git a/src/new_fields/util.ts b/src/new_fields/util.ts index 011e8c8d9..b2299f34a 100644 --- a/src/new_fields/util.ts +++ b/src/new_fields/util.ts @@ -5,8 +5,9 @@ import { ProxyField } from "./Proxy"; import { FieldValue } from "./Types"; import { RefField, Id } from "./RefField"; import { ObjectField, Parent, OnUpdate } from "./ObjectField"; +import { action } from "mobx"; -export function setter(target: any, prop: string | symbol | number, value: any, receiver: any): boolean { +export const setter = action(function (target: any, prop: string | symbol | number, value: any, receiver: any): boolean { if (SerializationHelper.IsSerializing()) { target[prop] = value; return true; @@ -46,7 +47,7 @@ export function setter(target: any, prop: string | symbol | number, value: any, undo: () => receiver[prop] = curValue }); return true; -} +}); export function getter(target: any, prop: string | symbol | number, receiver: any): any { if (typeof prop === "symbol") { diff --git a/src/server/database.ts b/src/server/database.ts index 6b3b6797f..4775c0eeb 100644 --- a/src/server/database.ts +++ b/src/server/database.ts @@ -60,19 +60,28 @@ export class Database { } public getDocument(id: string, fn: (result?: Transferable) => void, collectionName = Database.DocumentsCollection) { - console.log("getDocument"); - this.db && this.db.collection(collectionName).findOne({ id: id }, (err, result) => - fn(result ? ({ id: result._id, type: result.type, data: result.data }) : undefined)); + this.db && this.db.collection(collectionName).findOne({ _id: id }, (err, result) => { + if (result) { + result.id = result._id; + delete result._id; + fn(result); + } else { + fn(undefined); + } + }); } public getDocuments(ids: string[], fn: (result: Transferable[]) => void, collectionName = Database.DocumentsCollection) { - console.log("getDocuments"); - this.db && this.db.collection(collectionName).find({ id: { "$in": ids } }).toArray((err, docs) => { + this.db && this.db.collection(collectionName).find({ _id: { "$in": ids } }).toArray((err, docs) => { if (err) { console.log(err.message); console.log(err.errmsg); } - fn(docs.map(doc => ({ id: doc._id, type: doc.type, data: doc.data }))); + fn(docs.map(doc => { + doc.id = doc._id; + delete doc._id; + return doc; + })); }); } diff --git a/src/server/index.ts b/src/server/index.ts index 10158eb96..6801b3132 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -234,16 +234,18 @@ server.on("connection", function (socket: Socket) { Utils.AddServerHandler(socket, MessageStore.CreateField, CreateField); Utils.AddServerHandler(socket, MessageStore.UpdateField, diff => UpdateField(socket, diff)); - Utils.AddServerHandler(socket, MessageStore.GetRefField, GetRefField); - Utils.AddServerHandler(socket, MessageStore.GetRefFields, GetRefFields); + Utils.AddServerHandlerCallback(socket, MessageStore.GetRefField, GetRefField); + Utils.AddServerHandlerCallback(socket, MessageStore.GetRefFields, GetRefFields); }); -function deleteFields() { - return Database.Instance.deleteAll(); +async function deleteFields() { + await Database.Instance.deleteAll(); + await Database.Instance.deleteAll('newDocuments'); } async function deleteAll() { await Database.Instance.deleteAll(); + await Database.Instance.deleteAll('newDocuments'); await Database.Instance.deleteAll('sessions'); await Database.Instance.deleteAll('users'); } -- cgit v1.2.3-70-g09d2 From 9e6c6fe35d481a860145359f0df11d89b1c2329b Mon Sep 17 00:00:00 2001 From: bob Date: Mon, 29 Apr 2019 10:40:05 -0400 Subject: fixed histograms. --- .../northstar/core/filter/ValueComparision.ts | 6 +-- src/client/northstar/dash-nodes/HistogramBox.tsx | 54 +++++++++++----------- .../dash-nodes/HistogramLabelPrimitives.tsx | 8 ++-- .../northstar/operations/HistogramOperation.ts | 34 ++++++++++++-- 4 files changed, 64 insertions(+), 38 deletions(-) (limited to 'src/client/northstar') diff --git a/src/client/northstar/core/filter/ValueComparision.ts b/src/client/northstar/core/filter/ValueComparision.ts index 80b1242a9..65687a82b 100644 --- a/src/client/northstar/core/filter/ValueComparision.ts +++ b/src/client/northstar/core/filter/ValueComparision.ts @@ -62,13 +62,13 @@ export class ValueComparison { var rawName = this.attributeModel.CodeName; switch (this.Predicate) { case Predicate.STARTS_WITH: - ret += rawName + " !== null && " + rawName + ".StartsWith(" + val + ") "; + ret += rawName + " != null && " + rawName + ".StartsWith(" + val + ") "; return ret; case Predicate.ENDS_WITH: - ret += rawName + " !== null && " + rawName + ".EndsWith(" + val + ") "; + ret += rawName + " != null && " + rawName + ".EndsWith(" + val + ") "; return ret; case Predicate.CONTAINS: - ret += rawName + " !== null && " + rawName + ".Contains(" + val + ") "; + ret += rawName + " != null && " + rawName + ".Contains(" + val + ") "; return ret; default: ret += rawName + " " + op + " " + val + " "; diff --git a/src/client/northstar/dash-nodes/HistogramBox.tsx b/src/client/northstar/dash-nodes/HistogramBox.tsx index e2ecc8c83..ac5f3c8cf 100644 --- a/src/client/northstar/dash-nodes/HistogramBox.tsx +++ b/src/client/northstar/dash-nodes/HistogramBox.tsx @@ -1,7 +1,6 @@ import React = require("react"); 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"; import { Document } from "../../../fields/Document"; import { KeyStore } from "../../../fields/KeyStore"; @@ -31,8 +30,6 @@ export class HistogramBox extends React.Component { 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[] = []; @@ -88,7 +85,7 @@ export class HistogramBox extends React.Component { } 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.props.PanelWidth(), this.props.PanelHeight()], (size: number[]) => this.SizeConverter.SetIsSmall(size[0] < 40 && size[1] < 40)); reaction(() => this.HistogramResult ? this.HistogramResult.binRanges : undefined, (binRanges: BinRange[] | undefined) => { if (binRanges) { @@ -134,38 +131,39 @@ export class HistogramBox extends React.Component { })); } } + + @action + private onScrollWheel = (e: React.WheelEvent) => { + this.HistoOp.DrillDown(e.deltaY > 0); + e.stopPropagation(); + } + 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.Document.GetNumber(KeyStore.Height, 0); - var w = this.props.isTopMost ? this.PanelWidth : this.props.Document.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} -
-
- } -
+
+
+ + {labelY} + +
+
+ + +
+
+ {labelX} +
+
); } } diff --git a/src/client/northstar/dash-nodes/HistogramLabelPrimitives.tsx b/src/client/northstar/dash-nodes/HistogramLabelPrimitives.tsx index 5785fe838..62aebd3c6 100644 --- a/src/client/northstar/dash-nodes/HistogramLabelPrimitives.tsx +++ b/src/client/northstar/dash-nodes/HistogramLabelPrimitives.tsx @@ -12,7 +12,7 @@ import { HistogramPrimitivesProps } from "./HistogramBoxPrimitives"; @observer export class HistogramLabelPrimitives extends React.Component { componentDidMount() { - reaction(() => [this.props.HistoBox.PanelWidth, this.props.HistoBox.SizeConverter.LeftOffset, this.props.HistoBox.VisualBinRanges.length], + reaction(() => [this.props.HistoBox.props.PanelWidth(), this.props.HistoBox.SizeConverter.LeftOffset, this.props.HistoBox.VisualBinRanges.length], (fields) => HistogramLabelPrimitives.computeLabelAngle(fields[0], fields[1], this.props.HistoBox), { fireImmediately: true }); } @@ -35,7 +35,7 @@ export class HistogramLabelPrimitives extends React.ComponentFontStyles.AxisLabel.fontSize + 5))); sc.MaxLabelSizes[axis].coords[axis] + 5); @@ -49,12 +49,12 @@ export class HistogramLabelPrimitives extends React.Component diff --git a/src/client/northstar/operations/HistogramOperation.ts b/src/client/northstar/operations/HistogramOperation.ts index 760106023..6a8c9d8cf 100644 --- a/src/client/northstar/operations/HistogramOperation.ts +++ b/src/client/northstar/operations/HistogramOperation.ts @@ -23,7 +23,7 @@ export class HistogramOperation extends BaseOperation implements IBaseFilterCons @observable public Links: Document[] = []; @observable public BrushLinks: { l: Document, b: Document }[] = []; @observable public BrushColors: number[] = []; - @observable public FilterModels: FilterModel[] = []; + @observable public BarFilterModels: FilterModel[] = []; @observable public Normalization: number = -1; @observable public X: AttributeTransformationModel; @@ -50,17 +50,24 @@ export class HistogramOperation extends BaseOperation implements IBaseFilterCons throw new Error("Method not implemented."); } + + @computed public get FilterModels() { + return this.BarFilterModels; + } @action public AddFilterModels(filterModels: FilterModel[]): void { - filterModels.filter(f => f !== null).forEach(fm => this.FilterModels.push(fm)); + filterModels.filter(f => f !== null).forEach(fm => this.BarFilterModels.push(fm)); } @action public RemoveFilterModels(filterModels: FilterModel[]): void { - ArrayUtil.RemoveMany(this.FilterModels, filterModels); + ArrayUtil.RemoveMany(this.BarFilterModels, filterModels); } @computed public get FilterString(): string { + if (this.OverridingFilters.length > 0) { + return "(" + this.OverridingFilters.filter(fm => fm != null).map(fm => fm.ToPythonString()).join(" || ") + ")"; + } let filterModels: FilterModel[] = []; return FilterModel.GetFilterModelsRecursive(this, new Set(), filterModels, true); } @@ -79,6 +86,27 @@ export class HistogramOperation extends BaseOperation implements IBaseFilterCons return brushes; } + _stackedFilters: (FilterModel[])[] = []; + @action + public DrillDown(up: boolean) { + if (!up) { + if (!this.BarFilterModels.length) + return; + this._stackedFilters.push(this.BarFilterModels.map(f => f)); + this.OverridingFilters.length = 0; + this.OverridingFilters.push(...this._stackedFilters[this._stackedFilters.length - 1]); + this.BarFilterModels.map(fm => fm).map(fm => this.RemoveFilterModels([fm])); + //this.updateHistogram(); + } else { + this.OverridingFilters.length = 0; + if (this._stackedFilters.length) { + this.OverridingFilters.push(...this._stackedFilters.pop()!); + } + // else + // this.updateHistogram(); + } + } + 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)); -- cgit v1.2.3-70-g09d2 From ee31019f719b46db57de486e66158e9600515edd Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Tue, 30 Apr 2019 20:41:51 -0400 Subject: all non-list object field [Copy] implemented --- src/Utils.ts | 16 +++++++++++++++- src/client/northstar/dash-fields/HistogramField.ts | 4 ++-- src/new_fields/HtmlField.ts | 6 +++++- src/new_fields/IconField.ts | 6 +++++- src/new_fields/InkField.ts | 9 ++++++++- src/new_fields/List.ts | 6 +++++- src/new_fields/ObjectField.ts | 12 ++++++------ src/new_fields/Proxy.ts | 14 +++++++++++--- src/new_fields/RichTextField.ts | 6 +++++- src/new_fields/URLField.ts | 6 +++++- 10 files changed, 67 insertions(+), 18 deletions(-) (limited to 'src/client/northstar') diff --git a/src/Utils.ts b/src/Utils.ts index c1ad88e2f..d4b6f5377 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -116,4 +116,18 @@ export function returnZero() { return 0; } export function emptyFunction() { } -export type Without = Pick>; \ No newline at end of file +export type Without = Pick>; + +export type Predicate = (entry: [K, V]) => boolean; + +export function deepCopy(source: Map, predicate?: Predicate) { + let deepCopy = new Map(); + let entries = source.entries(), next = entries.next(); + while (!next.done) { + let entry = next.value; + if (!predicate || predicate(entry)) { + deepCopy.set(entry[0], entry[1]); + } + } + return deepCopy; +} \ No newline at end of file diff --git a/src/client/northstar/dash-fields/HistogramField.ts b/src/client/northstar/dash-fields/HistogramField.ts index 730289536..f01f08487 100644 --- a/src/client/northstar/dash-fields/HistogramField.ts +++ b/src/client/northstar/dash-fields/HistogramField.ts @@ -3,7 +3,7 @@ import { custom, serializable } from "serializr"; import { ColumnAttributeModel } from "../../../client/northstar/core/attribute/AttributeModel"; import { AttributeTransformationModel } from "../../../client/northstar/core/attribute/AttributeTransformationModel"; import { HistogramOperation } from "../../../client/northstar/operations/HistogramOperation"; -import { ObjectField } from "../../../new_fields/ObjectField"; +import { ObjectField, Copy } from "../../../new_fields/ObjectField"; import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils"; import { OmitKeys } from "../../../Utils"; import { Deserializable } from "../../util/SerializationHelper"; @@ -49,7 +49,7 @@ export class HistogramField extends ObjectField { return JSON.stringify(OmitKeys(this.HistoOp, ['Links', 'BrushLinks', 'Result', 'BrushColors', 'FilterModels', 'FilterOperand']).omit); } - Copy(): HistogramField { + [Copy]() { return new HistogramField(this.HistoOp.Copy()); } } \ No newline at end of file diff --git a/src/new_fields/HtmlField.ts b/src/new_fields/HtmlField.ts index 808a3499b..d998746bb 100644 --- a/src/new_fields/HtmlField.ts +++ b/src/new_fields/HtmlField.ts @@ -1,6 +1,6 @@ import { Deserializable } from "../client/util/SerializationHelper"; import { serializable, primitive } from "serializr"; -import { ObjectField } from "./ObjectField"; +import { ObjectField, Copy } from "./ObjectField"; @Deserializable("html") export class HtmlField extends ObjectField { @@ -11,4 +11,8 @@ export class HtmlField extends ObjectField { super(); this.html = html; } + + [Copy]() { + return new HtmlField(this.html); + } } diff --git a/src/new_fields/IconField.ts b/src/new_fields/IconField.ts index c79a2f79a..1a928389d 100644 --- a/src/new_fields/IconField.ts +++ b/src/new_fields/IconField.ts @@ -1,6 +1,6 @@ import { Deserializable } from "../client/util/SerializationHelper"; import { serializable, primitive } from "serializr"; -import { ObjectField } from "./ObjectField"; +import { ObjectField, Copy } from "./ObjectField"; @Deserializable("icon") export class IconField extends ObjectField { @@ -11,4 +11,8 @@ export class IconField extends ObjectField { super(); this.icon = icon; } + + [Copy]() { + return new IconField(this.icon); + } } diff --git a/src/new_fields/InkField.ts b/src/new_fields/InkField.ts index f95952c2e..86a8bd18a 100644 --- a/src/new_fields/InkField.ts +++ b/src/new_fields/InkField.ts @@ -1,6 +1,9 @@ import { Deserializable } from "../client/util/SerializationHelper"; import { serializable, custom, createSimpleSchema, list, object, map } from "serializr"; -import { ObjectField } from "./ObjectField"; +import { ObjectField, Copy } from "./ObjectField"; +import { number } from "prop-types"; +import { any } from "bluebird"; +import { deepCopy } from "../Utils"; export enum InkTool { None, @@ -34,4 +37,8 @@ export class InkField extends ObjectField { super(); this.inkData = data || new Map; } + + [Copy]() { + return new InkField(deepCopy(this.inkData)) + } } diff --git a/src/new_fields/List.ts b/src/new_fields/List.ts index ec1bf44a9..c1bd15cd1 100644 --- a/src/new_fields/List.ts +++ b/src/new_fields/List.ts @@ -3,7 +3,7 @@ import { Field, Update, Self } from "./Doc"; import { setter, getter, deleteProperty } from "./util"; import { serializable, alias, list } from "serializr"; import { observable, observe, IArrayChange, IArraySplice, IObservableArray, Lambda, reaction } from "mobx"; -import { ObjectField, OnUpdate } from "./ObjectField"; +import { ObjectField, OnUpdate, Copy } from "./ObjectField"; import { RefField } from "./RefField"; import { ProxyField } from "./Proxy"; @@ -215,6 +215,10 @@ class ListImpl extends ObjectField { this.___fields = value; } + [Copy]() { + return new ListImpl(); + } + // @serializable(alias("fields", list(autoObject()))) @observable private ___fields: (T | null | undefined)[]; diff --git a/src/new_fields/ObjectField.ts b/src/new_fields/ObjectField.ts index 9cac2c528..0f3777af6 100644 --- a/src/new_fields/ObjectField.ts +++ b/src/new_fields/ObjectField.ts @@ -2,16 +2,16 @@ import { Doc } from "./Doc"; export const OnUpdate = Symbol("OnUpdate"); export const Parent = Symbol("Parent"); -const Id = Symbol("Object Id"); -export class ObjectField { +export const Copy = Symbol("Copy"); + +export abstract class ObjectField { protected [OnUpdate]?: (diff?: any) => void; private [Parent]?: Doc; - readonly [Id] = ""; + abstract [Copy](): ObjectField; } export namespace ObjectField { - export function MakeCopy(field: ObjectField) { - //TODO Types - return field; + export function MakeCopy(field: T) { + return field[Copy](); } } diff --git a/src/new_fields/Proxy.ts b/src/new_fields/Proxy.ts index 56e41cc0f..fd99ae1c0 100644 --- a/src/new_fields/Proxy.ts +++ b/src/new_fields/Proxy.ts @@ -4,20 +4,28 @@ import { primitive, serializable } from "serializr"; import { observable, action } from "mobx"; import { DocServer } from "../client/DocServer"; import { RefField, Id } from "./RefField"; -import { ObjectField } from "./ObjectField"; +import { ObjectField, Copy } from "./ObjectField"; @Deserializable("proxy") export class ProxyField extends ObjectField { constructor(); constructor(value: T); - constructor(value?: T) { + constructor(fieldId: string); + constructor(value?: T | string) { super(); - if (value) { + if (typeof value === "string") { + this.fieldId = value; + } else if (value) { this.cache = value; this.fieldId = value[Id]; } } + [Copy]() { + if (this.cache) return new ProxyField(this.cache); + return new ProxyField(this.fieldId); + } + @serializable(primitive()) readonly fieldId: string = ""; diff --git a/src/new_fields/RichTextField.ts b/src/new_fields/RichTextField.ts index f2033d5a7..eb30e76de 100644 --- a/src/new_fields/RichTextField.ts +++ b/src/new_fields/RichTextField.ts @@ -1,4 +1,4 @@ -import { ObjectField } from "./ObjectField"; +import { ObjectField, Copy } from "./ObjectField"; import { serializable } from "serializr"; import { Deserializable } from "../client/util/SerializationHelper"; @@ -11,4 +11,8 @@ export class RichTextField extends ObjectField { super(); this.Data = data; } + + [Copy]() { + return new RichTextField(this.Data); + } } \ No newline at end of file diff --git a/src/new_fields/URLField.ts b/src/new_fields/URLField.ts index 95c679df7..d7120a5d2 100644 --- a/src/new_fields/URLField.ts +++ b/src/new_fields/URLField.ts @@ -1,6 +1,6 @@ import { Deserializable } from "../client/util/SerializationHelper"; import { serializable, custom } from "serializr"; -import { ObjectField } from "./ObjectField"; +import { ObjectField, Copy } from "./ObjectField"; function url() { return custom( @@ -21,6 +21,10 @@ export class URLField extends ObjectField { super(); this.url = url; } + + [Copy]() { + return new URLField(this.url); + } } @Deserializable("audio") export class AudioField extends URLField { } -- cgit v1.2.3-70-g09d2 From c9f3a1934548169ebe3c2e97968680ff339e304e Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Sat, 4 May 2019 18:59:30 -0400 Subject: initial commit - todo: use cursor field rather than generic tuple field --- .../northstar/operations/HistogramOperation.ts | 5 +- src/client/util/DragManager.ts | 8 +-- src/client/views/DocumentDecorations.tsx | 2 +- src/client/views/PresentationView.tsx | 4 +- src/client/views/PreviewCursor.tsx | 4 +- .../views/collections/CollectionDockingView.tsx | 6 ++- src/client/views/collections/CollectionSubView.tsx | 9 ++-- .../views/collections/CollectionTreeView.tsx | 4 +- .../views/collections/CollectionVideoView.tsx | 2 +- .../collections/collectionFreeForm/MarqueeView.tsx | 7 +-- .../views/nodes/CollectionFreeFormDocumentView.tsx | 9 ++-- src/client/views/nodes/FormattedTextBox.tsx | 8 +-- src/client/views/nodes/PDFBox.tsx | 5 +- src/new_fields/InkField.ts | 2 +- src/new_fields/ObjectField.ts | 2 +- src/new_fields/TupleField.ts | 63 ++++++++++++++++++++++ 16 files changed, 106 insertions(+), 34 deletions(-) create mode 100644 src/new_fields/TupleField.ts (limited to 'src/client/northstar') diff --git a/src/client/northstar/operations/HistogramOperation.ts b/src/client/northstar/operations/HistogramOperation.ts index 5c9c832c0..78b206bdc 100644 --- a/src/client/northstar/operations/HistogramOperation.ts +++ b/src/client/northstar/operations/HistogramOperation.ts @@ -65,7 +65,7 @@ export class HistogramOperation extends BaseOperation implements IBaseFilterCons @computed public get FilterString(): string { if (this.OverridingFilters.length > 0) { - return "(" + this.OverridingFilters.filter(fm => fm != null).map(fm => fm.ToPythonString()).join(" || ") + ")"; + return "(" + this.OverridingFilters.filter(fm => fm !== null).map(fm => fm.ToPythonString()).join(" || ") + ")"; } let filterModels: FilterModel[] = []; return FilterModel.GetFilterModelsRecursive(this, new Set(), filterModels, true); @@ -89,8 +89,9 @@ export class HistogramOperation extends BaseOperation implements IBaseFilterCons @action public DrillDown(up: boolean) { if (!up) { - if (!this.BarFilterModels.length) + if (!this.BarFilterModels.length) { return; + } this._stackedFilters.push(this.BarFilterModels.map(f => f)); this.OverridingFilters.length = 0; this.OverridingFilters.push(...this._stackedFilters[this._stackedFilters.length - 1]); diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index a3dbe6e43..8f27f5b21 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -155,9 +155,9 @@ export namespace DragManager { export function StartDocumentDrag(eles: HTMLElement[], dragData: DocumentDragData, downX: number, downY: number, options?: DragOptions) { StartDrag(eles, dragData, downX, downY, options, (dropData: { [id: string]: any }) => - (dropData.droppedDocuments = dragData.userDropAction == "alias" || (!dragData.userDropAction && dragData.dropAction == "alias") ? + (dropData.droppedDocuments = dragData.userDropAction === "alias" || (!dragData.userDropAction && dragData.dropAction === "alias") ? dragData.draggedDocuments.map(d => Doc.MakeAlias(d)) : - dragData.userDropAction == "copy" || (!dragData.userDropAction && dragData.dropAction == "copy") ? + dragData.userDropAction === "copy" || (!dragData.userDropAction && dragData.dropAction === "copy") ? dragData.draggedDocuments.map(d => Doc.MakeCopy(d, true)) : dragData.draggedDocuments)); } @@ -280,7 +280,7 @@ export namespace DragManager { }; let hideDragElements = () => { - dragElements.map(dragElement => dragElement.parentNode == dragDiv && dragDiv.removeChild(dragElement)); + dragElements.map(dragElement => dragElement.parentNode === dragDiv && dragDiv.removeChild(dragElement)); eles.map(ele => (ele.hidden = false)); }; let endDrag = () => { @@ -289,7 +289,7 @@ export namespace DragManager { if (options) { options.handlers.dragComplete({}); } - } + }; AbortDrag = () => { hideDragElements(); diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 693d6ec55..16e5b6b48 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -278,7 +278,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> iconDoc = this.createIcon([docView], layout); } if (SelectionManager.SelectedDocuments()[0].props.addDocument !== undefined) { - SelectionManager.SelectedDocuments()[0].props.addDocument!(iconDoc!); + SelectionManager.SelectedDocuments()[0].props.addDocument!(iconDoc); } return iconDoc; } diff --git a/src/client/views/PresentationView.tsx b/src/client/views/PresentationView.tsx index b4c12d057..d8bdbacca 100644 --- a/src/client/views/PresentationView.tsx +++ b/src/client/views/PresentationView.tsx @@ -1,7 +1,7 @@ import { observer } from "mobx-react"; -import React = require("react") +import React = require("react"); import { observable, action } from "mobx"; -import "./PresentationView.scss" +import "./PresentationView.scss"; import "./Main.tsx"; import { DocumentManager } from "../util/DocumentManager"; import { Utils } from "../../Utils"; diff --git a/src/client/views/PreviewCursor.tsx b/src/client/views/PreviewCursor.tsx index 4359ba093..9520f489c 100644 --- a/src/client/views/PreviewCursor.tsx +++ b/src/client/views/PreviewCursor.tsx @@ -17,7 +17,7 @@ export class PreviewCursor extends React.Component<{}> { constructor(props: any) { super(props); - document.addEventListener("keydown", this.onKeyPress) + document.addEventListener("keydown", this.onKeyPress); } @action @@ -27,7 +27,7 @@ export class PreviewCursor extends React.Component<{}> { // the keyPress here. //if not these keys, make a textbox if preview cursor is active! if (e.key.startsWith("F") && !e.key.endsWith("F")) { - } else if (e.key != "Escape" && e.key != "Alt" && e.key != "Shift" && e.key != "Meta" && e.key != "Control" && !e.defaultPrevented && !(e as any).DASHFormattedTextBoxHandled) { + } else if (e.key !== "Escape" && e.key !== "Alt" && e.key !== "Shift" && e.key !== "Meta" && e.key !== "Control" && !e.defaultPrevented && !(e as any).DASHFormattedTextBoxHandled) { if ((!e.ctrlKey && !e.metaKey) || e.key === "v") { PreviewCursor.Visible && PreviewCursor._onKeyPress && PreviewCursor._onKeyPress(e); PreviewCursor.Visible = false; diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index cfb1aef7d..725f0ab51 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -350,13 +350,15 @@ export class DockedFrameRenderer extends React.Component { get previewPanelCenteringOffset() { return (this._panelWidth - this.nativeWidth() * this.contentScaling()) / 2; } get content() { - if (!this._document) + if (!this._document) { return (null); + } return (
- boolean; @@ -66,12 +67,12 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T) { if (!proto) { return; } - let cursors = await Cast(proto.cursors, listSpec(ObjectField)); + let cursors = await Cast(proto!.cursors, listSpec(TupleField)); if (!cursors) { - proto.cursors = cursors = new List(); + proto!.cursors = cursors = new List>(); } - if (cursors.length > 0 && (ind = cursors.findIndex(entry => entry.Data[0][0] === id)) > -1) { - cursors[ind].Data[1] = position; + if (cursors!.length > 0 && (ind = cursors!.findIndex(entry => entry.data[0][0] === id)) > -1) { + cursors![ind].data[1] = position; } else { let entry = new TupleField<[string, string], [number, number]>([textInfo, position]); cursors.push(entry); diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index b67d6f965..7898d74ce 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -117,8 +117,8 @@ class TreeView extends React.Component { } } - onPointerEnter = (e: React.PointerEvent): void => { this.props.document.libraryBrush = true; } - onPointerLeave = (e: React.PointerEvent): void => { this.props.document.libraryBrush = false; } + onPointerEnter = (e: React.PointerEvent): void => { this.props.document.libraryBrush = true; }; + onPointerLeave = (e: React.PointerEvent): void => { this.props.document.libraryBrush = false; }; render() { let bulletType = BulletType.List; diff --git a/src/client/views/collections/CollectionVideoView.tsx b/src/client/views/collections/CollectionVideoView.tsx index 9dee217cb..cb3fd1ba4 100644 --- a/src/client/views/collections/CollectionVideoView.tsx +++ b/src/client/views/collections/CollectionVideoView.tsx @@ -90,7 +90,7 @@ export class CollectionVideoView extends React.Component { } } - setVideoBox = (player: VideoBox) => { this._videoBox = player; } + setVideoBox = (player: VideoBox) => { this._videoBox = player; }; private subView = (_type: CollectionViewType, renderProps: CollectionRenderProps) => { let props = { ...this.props, ...renderProps }; diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 8c81f6990..a9e627188 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -139,7 +139,7 @@ export class MarqueeView extends React.Component if (this._commandExecuted) { return; } - if (e.key === "Backspace" || e.key === "Delete" || e.key == "d") { + if (e.key === "Backspace" || e.key === "Delete" || e.key === "d") { this._commandExecuted = true; this.marqueeSelect().map(d => this.props.removeDocument(d)); let ink = Cast(this.props.container.props.Document.ink, InkField); @@ -154,8 +154,9 @@ export class MarqueeView extends React.Component e.stopPropagation(); let bounds = this.Bounds; let selected = this.marqueeSelect().map(d => { - if (e.key !== "r") + if (e.key !== "r") { this.props.removeDocument(d); + } d.x = NumCast(d.x) - bounds.left - bounds.width / 2; d.y = NumCast(d.y) - bounds.top - bounds.height / 2; d.page = -1; @@ -194,7 +195,7 @@ export class MarqueeView extends React.Component let maxy = NumCast(maximizedDoc.y, undefined); let maxw = NumCast(maximizedDoc.width, undefined); let maxh = NumCast(maximizedDoc.height, undefined); - maximizedDoc.isIconAnimating = new List([scrpt[0], scrpt[1], maxx, maxy, maxw, maxh, Date.now(), 0]) + maximizedDoc.isIconAnimating = new List([scrpt[0], scrpt[1], maxx, maxy, maxw, maxh, Date.now(), 0]); }); } else { diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 2ba0458f5..6186cf348 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -148,7 +148,7 @@ export class CollectionFreeFormDocumentView extends DocComponent([scrpt[0], scrpt[1], maxx, maxy, maxw, maxh, Date.now(), isMinimized ? 1 : 0]) + maximizedDoc.isIconAnimating = new List([scrpt[0], scrpt[1], maxx, maxy, maxw, maxh, Date.now(), isMinimized ? 1 : 0]); } } }); @@ -167,16 +167,17 @@ export class CollectionFreeFormDocumentView extends DocComponent d instanceof Doc).map(maxDoc => this.props.addDocument!(maxDoc, false)); + } this.toggleIcon(); } } } } - onPointerEnter = (e: React.PointerEvent): void => { this.props.Document.libraryBrush = true; } - onPointerLeave = (e: React.PointerEvent): void => { this.props.Document.libraryBrush = false; } + onPointerEnter = (e: React.PointerEvent): void => { this.props.Document.libraryBrush = true; }; + onPointerLeave = (e: React.PointerEvent): void => { this.props.Document.libraryBrush = false; }; borderRounding = () => { let br = NumCast(this.props.Document.borderRounding); diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index eeb60cb3d..3873dfd62 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -91,7 +91,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe let titlestr = str.substr(0, Math.min(40, str.length)); let target = this.props.Document.proto ? this.props.Document.proto : this.props.Document; target.title = "-" + titlestr + (str.length > 40 ? "..." : ""); - }; + } } } @@ -176,8 +176,9 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe onPointerDown = (e: React.PointerEvent): void => { if (e.button === 0 && this.props.isSelected() && !e.altKey && !e.ctrlKey && !e.metaKey) { e.stopPropagation(); - if (this._toolTipTextMenu && this._toolTipTextMenu.tooltip) + if (this._toolTipTextMenu && this._toolTipTextMenu.tooltip) { this._toolTipTextMenu.tooltip.style.opacity = "0"; + } } if (e.button === 2 || (e.button === 0 && e.ctrlKey)) { this._gotDown = true; @@ -185,8 +186,9 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe } } onPointerUp = (e: React.PointerEvent): void => { - if (this._toolTipTextMenu && this._toolTipTextMenu.tooltip) + if (this._toolTipTextMenu && this._toolTipTextMenu.tooltip) { this._toolTipTextMenu.tooltip.style.opacity = "1"; + } if (e.buttons === 1 && this.props.isSelected() && !e.altKey) { e.stopPropagation(); } diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index eb45ea273..caa66cbeb 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -215,8 +215,9 @@ export class PDFBox extends DocComponent(PdfDocumen if (e.altKey) { this._alt = true; } else { - if (e.metaKey) + if (e.metaKey) { e.stopPropagation(); + } } document.removeEventListener("pointerup", this.onPointerUp); document.addEventListener("pointerup", this.onPointerUp); @@ -286,7 +287,7 @@ export class PDFBox extends DocComponent(PdfDocumen renderHeight = 2400; @computed get pdfPage() { - return + return ; } @computed get pdfContent() { diff --git a/src/new_fields/InkField.ts b/src/new_fields/InkField.ts index 86a8bd18a..a3157857f 100644 --- a/src/new_fields/InkField.ts +++ b/src/new_fields/InkField.ts @@ -39,6 +39,6 @@ export class InkField extends ObjectField { } [Copy]() { - return new InkField(deepCopy(this.inkData)) + return new InkField(deepCopy(this.inkData)); } } diff --git a/src/new_fields/ObjectField.ts b/src/new_fields/ObjectField.ts index 0f3777af6..715c6a924 100644 --- a/src/new_fields/ObjectField.ts +++ b/src/new_fields/ObjectField.ts @@ -5,7 +5,7 @@ export const Parent = Symbol("Parent"); export const Copy = Symbol("Copy"); export abstract class ObjectField { - protected [OnUpdate]?: (diff?: any) => void; + protected [OnUpdate](diff?: any) { }; private [Parent]?: Doc; abstract [Copy](): ObjectField; } diff --git a/src/new_fields/TupleField.ts b/src/new_fields/TupleField.ts new file mode 100644 index 000000000..1ff57fefc --- /dev/null +++ b/src/new_fields/TupleField.ts @@ -0,0 +1,63 @@ +import { ObjectField, Copy } from "./ObjectField"; +import { IObservableArray, IArrayChange, IArraySplice, observe, Lambda, observable } from "mobx"; +import { UndoManager } from "../client/util/UndoManager"; +import { Field } from "./Doc"; +import { Deserializable } from "../client/util/SerializationHelper"; +import { serializable, createSimpleSchema, list, object } from "serializr"; +import { array } from "prop-types"; + +const tupleSchema = createSimpleSchema({ + +}); + +@Deserializable("tuple") +export class TupleField extends ObjectField { + + + @serializable(list(object(tupleSchema))) + private Data: [T, U]; + + public get data() { + return this.Data; + } + + constructor(data: [T, U]) { + super(); + this.Data = data; + this.observeTuple(); + } + + private observeDisposer: Lambda | undefined; + private observeTuple(): void { + this.observeDisposer = observe(this.Data as (T | U)[] as IObservableArray, (change: IArrayChange | IArraySplice) => { + if (change.type === "update") { + UndoManager.AddEvent({ + undo: () => this.Data[change.index] = change.oldValue, + redo: () => this.Data[change.index] = change.newValue + }); + } else { + throw new Error("Why are you messing with the length of a tuple, huh?"); + } + }); + } + + protected setData(value: [T, U]) { + if (this.observeDisposer) { + this.observeDisposer(); + } + this.Data = observable(value) as (T | U)[] as [T, U]; + this.observeTuple(); + } + + UpdateFromServer(values: [T, U]) { + this.setData(values); + } + + ToScriptString(): string { + return `new TupleField([${this.Data[0], this.Data[1]}])`; + } + + [Copy]() { + return new TupleField(this.Data); + } +} \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 168cd36282087bbf9e0157352a129d90b20b7394 Mon Sep 17 00:00:00 2001 From: bob Date: Thu, 9 May 2019 14:40:03 -0400 Subject: fixed some compile errors --- src/client/northstar/dash-nodes/HistogramBox.tsx | 8 ++++---- src/client/util/DocumentManager.ts | 2 +- src/client/views/DocumentDecorations.tsx | 1 + src/client/views/collections/CollectionBaseView.tsx | 4 ++-- src/client/views/collections/CollectionSchemaView.tsx | 2 +- src/client/views/nodes/FieldView.tsx | 3 ++- src/client/views/nodes/LinkMenu.tsx | 4 ++-- 7 files changed, 13 insertions(+), 11 deletions(-) (limited to 'src/client/northstar') diff --git a/src/client/northstar/dash-nodes/HistogramBox.tsx b/src/client/northstar/dash-nodes/HistogramBox.tsx index 765ecf8f0..5e7b867b3 100644 --- a/src/client/northstar/dash-nodes/HistogramBox.tsx +++ b/src/client/northstar/dash-nodes/HistogramBox.tsx @@ -117,15 +117,15 @@ export class HistogramBox extends React.Component { runInAction(() => { this.HistoOp = histoOp ? histoOp.HistoOp : HistogramOperation.Empty; if (this.HistoOp !== HistogramOperation.Empty) { - reaction(() => Cast(this.props.Document.linkedFromDocs, listSpec(Doc), []), (docs) => this.HistoOp.Links.splice(0, this.HistoOp.Links.length, ...docs), { fireImmediately: true }); + reaction(() => Cast(this.props.Document.linkedFromDocs, listSpec(Doc), []).filter(d => d).map(d => d as Doc), (docs) => this.HistoOp.Links.splice(0, this.HistoOp.Links.length, ...docs), { fireImmediately: true }); reaction(() => Cast(this.props.Document.brushingDocs, listSpec(Doc), []).length, () => { - let brushingDocs = Cast(this.props.Document.brushingDocs, listSpec(Doc), []); + let brushingDocs = Cast(this.props.Document.brushingDocs, listSpec(Doc), []).filter(d => d).map(d => d as Doc); const proto = this.props.Document.proto; if (proto) { this.HistoOp.BrushLinks.splice(0, this.HistoOp.BrushLinks.length, ...brushingDocs.map((brush, i) => { - brush.bckgroundColor = StyleConstants.BRUSH_COLORS[i % StyleConstants.BRUSH_COLORS.length]; - let brushed = Cast(brush.brushingDocs, listSpec(Doc), []); + brush.backgroundColor = StyleConstants.BRUSH_COLORS[i % StyleConstants.BRUSH_COLORS.length]; + let brushed = Cast(brush.brushingDocs, listSpec(Doc), []).filter(d => d).map(d => d as Doc); return { l: brush, b: brushed[0][Id] === proto[Id] ? brushed[1] : brushed[0] }; })); } diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index 69964e2c9..4c264c7ec 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -71,7 +71,7 @@ export class DocumentManager { @computed public get LinkedDocumentViews() { return DocumentManager.Instance.DocumentViews.reduce((pairs, dv) => { - let linksList = Cast(dv.props.Document.linkedToDocs, listSpec(Doc)); + let linksList = Cast(dv.props.Document.linkedToDocs, listSpec(Doc), []).filter(d => d).map(d => d as Doc); if (linksList && linksList.length) { pairs.push(...linksList.reduce((pairs, link) => { if (link) { diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 2bde4e0c8..705e7a6d8 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -27,6 +27,7 @@ import { MINIMIZED_ICON_SIZE } from "../views/globalCssVariables.scss"; import { CollectionView } from "./collections/CollectionView"; import { DocumentManager } from "../util/DocumentManager"; import { FormattedTextBox } from "./nodes/FormattedTextBox"; +import { FieldView } from "./nodes/FieldView"; library.add(faLink); diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx index 14b92af48..2b1f7bb37 100644 --- a/src/client/views/collections/CollectionBaseView.tsx +++ b/src/client/views/collections/CollectionBaseView.tsx @@ -63,13 +63,13 @@ export class CollectionBaseView extends React.Component { if (!(documentToAdd instanceof Doc)) { return false; } - let data = Cast(documentToAdd.data, listSpec(Doc), []); + let data = Cast(documentToAdd.data, listSpec(Doc), []).filter(d => d).map(d => d as Doc); for (const doc of data.filter(d => d instanceof Document)) { if (this.createsCycle(doc, containerDocument)) { return true; } } - let annots = Cast(documentToAdd.annotations, listSpec(Doc), []); + let annots = Cast(documentToAdd.annotations, listSpec(Doc), []).filter(d => d).map(d => d as Doc); for (const annot of annots) { if (this.createsCycle(annot, containerDocument)) { return true; diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index 6dd0e5935..ae949b2ed 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -276,7 +276,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { } get documentKeysCheckList() { - const docs = Cast(this.props.Document[this.props.fieldKey], listSpec(Doc), []); + const docs = Cast(this.props.Document[this.props.fieldKey], listSpec(Doc), []).filter(d => d).map(d => d as Doc); let keys: { [key: string]: boolean } = {}; // bcz: ugh. this is untracked since otherwise a large collection of documents will blast the server for all their fields. // then as each document's fields come back, we update the documents _proxies. Each time we do this, the whole schema will be diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index cdc1bdc85..8bdf34181 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -99,7 +99,8 @@ export class FieldView extends React.Component { ContainingCollectionView={this.props.ContainingCollectionView} parentActive={this.props.active} toggleMinimized={emptyFunction} - whenActiveChanged={this.props.whenActiveChanged} /> + whenActiveChanged={this.props.whenActiveChanged} + bringToFront={emptyFunction} /> ); } else if (field instanceof List) { diff --git a/src/client/views/nodes/LinkMenu.tsx b/src/client/views/nodes/LinkMenu.tsx index e21adebbc..24901913d 100644 --- a/src/client/views/nodes/LinkMenu.tsx +++ b/src/client/views/nodes/LinkMenu.tsx @@ -31,8 +31,8 @@ export class LinkMenu extends React.Component { render() { //get list of links from document - let linkFrom: Doc[] = Cast(this.props.docView.props.Document.linkedFromDocs, listSpec(Doc), []); - let linkTo: Doc[] = Cast(this.props.docView.props.Document.linkedToDocs, listSpec(Doc), []); + let linkFrom = Cast(this.props.docView.props.Document.linkedFromDocs, listSpec(Doc), []).filter(d => d).map(d => d as Doc); + let linkTo = Cast(this.props.docView.props.Document.linkedToDocs, listSpec(Doc), []).filter(d => d).map(d => d as Doc); if (this._editingLink === undefined) { return (
-- cgit v1.2.3-70-g09d2 From 7da76d2538ebde21d7a878b5096d5a673e5d6375 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Fri, 10 May 2019 23:01:08 -0400 Subject: added summary screen grab icon as a template view of a text document. converted Cast(...ListSpec(Doc)) pattern to DocListCast --- src/client/northstar/dash-nodes/HistogramBox.tsx | 10 +++---- src/client/util/DocumentManager.ts | 6 ++-- src/client/util/DragManager.ts | 6 ++-- src/client/views/PresentationView.tsx | 11 +++++-- src/client/views/Templates.tsx | 35 +++++++++++++++------- .../views/collections/CollectionBaseView.tsx | 8 ++--- .../views/collections/CollectionSchemaView.tsx | 6 ++-- src/client/views/collections/CollectionSubView.tsx | 4 +-- .../views/collections/CollectionTreeView.tsx | 22 +++++++------- .../CollectionFreeFormLinksView.tsx | 12 ++++---- .../collections/collectionFreeForm/MarqueeView.tsx | 24 +++++++++++---- .../views/nodes/CollectionFreeFormDocumentView.tsx | 28 +++++++++-------- src/client/views/nodes/DocumentView.tsx | 23 +++++++------- src/client/views/nodes/IconBox.tsx | 4 +-- src/client/views/nodes/ImageBox.tsx | 14 ++++++--- src/client/views/nodes/LinkMenu.tsx | 6 ++-- src/new_fields/Doc.ts | 10 +++++-- 17 files changed, 137 insertions(+), 92 deletions(-) (limited to 'src/client/northstar') diff --git a/src/client/northstar/dash-nodes/HistogramBox.tsx b/src/client/northstar/dash-nodes/HistogramBox.tsx index 5e7b867b3..ed556cf45 100644 --- a/src/client/northstar/dash-nodes/HistogramBox.tsx +++ b/src/client/northstar/dash-nodes/HistogramBox.tsx @@ -19,7 +19,7 @@ import { HistogramLabelPrimitives } from "./HistogramLabelPrimitives"; import { StyleConstants } from "../utils/StyleContants"; import { NumCast, Cast } from "../../../new_fields/Types"; import { listSpec } from "../../../new_fields/Schema"; -import { Doc } from "../../../new_fields/Doc"; +import { Doc, DocListCast } from "../../../new_fields/Doc"; import { Id } from "../../../new_fields/RefField"; @@ -117,15 +117,15 @@ export class HistogramBox extends React.Component { runInAction(() => { this.HistoOp = histoOp ? histoOp.HistoOp : HistogramOperation.Empty; if (this.HistoOp !== HistogramOperation.Empty) { - reaction(() => Cast(this.props.Document.linkedFromDocs, listSpec(Doc), []).filter(d => d).map(d => d as Doc), (docs) => this.HistoOp.Links.splice(0, this.HistoOp.Links.length, ...docs), { fireImmediately: true }); - reaction(() => Cast(this.props.Document.brushingDocs, listSpec(Doc), []).length, + reaction(() => DocListCast(this.props.Document.linkedFromDocs), (docs) => this.HistoOp.Links.splice(0, this.HistoOp.Links.length, ...docs), { fireImmediately: true }); + reaction(() => DocListCast(this.props.Document.brushingDocs).length, () => { - let brushingDocs = Cast(this.props.Document.brushingDocs, listSpec(Doc), []).filter(d => d).map(d => d as Doc); + let brushingDocs = DocListCast(this.props.Document.brushingDocs); const proto = this.props.Document.proto; if (proto) { this.HistoOp.BrushLinks.splice(0, this.HistoOp.BrushLinks.length, ...brushingDocs.map((brush, i) => { brush.backgroundColor = StyleConstants.BRUSH_COLORS[i % StyleConstants.BRUSH_COLORS.length]; - let brushed = Cast(brush.brushingDocs, listSpec(Doc), []).filter(d => d).map(d => d as Doc); + let brushed = DocListCast(brush.brushingDocs); return { l: brush, b: brushed[0][Id] === proto[Id] ? brushed[1] : brushed[0] }; })); } diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index a8b643d4d..9a7a94228 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -1,6 +1,6 @@ import { computed, observable } from 'mobx'; import { DocumentView } from '../views/nodes/DocumentView'; -import { Doc } from '../../new_fields/Doc'; +import { Doc, DocListCast } from '../../new_fields/Doc'; import { FieldValue, Cast, NumCast, BoolCast } from '../../new_fields/Types'; import { listSpec } from '../../new_fields/Schema'; import { undoBatch } from './UndoManager'; @@ -73,7 +73,7 @@ export class DocumentManager { @computed public get LinkedDocumentViews() { return DocumentManager.Instance.DocumentViews.filter(dv => dv.isSelected() || BoolCast(dv.props.Document.libraryBrush, false)).reduce((pairs, dv) => { - let linksList = Cast(dv.props.Document.linkedToDocs, listSpec(Doc), []).filter(d => d).map(d => d as Doc); + let linksList = DocListCast(dv.props.Document.linkedToDocs); if (linksList && linksList.length) { pairs.push(...linksList.reduce((pairs, link) => { if (link) { @@ -86,7 +86,7 @@ export class DocumentManager { return pairs; }, [] as { a: DocumentView, b: DocumentView, l: Doc }[])); } - linksList = Cast(dv.props.Document.linkedFromDocs, listSpec(Doc), []).filter(d => d).map(d => d as Doc); + linksList = DocListCast(dv.props.Document.linkedFromDocs); if (linksList && linksList.length) { pairs.push(...linksList.reduce((pairs, link) => { if (link) { diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index c0402f0c9..2da0d5b51 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -1,5 +1,5 @@ import { action, runInAction } from "mobx"; -import { Doc, DocListCast } from "../../new_fields/Doc"; +import { Doc, DocListCastAsync } from "../../new_fields/Doc"; import { Cast } from "../../new_fields/Types"; import { emptyFunction } from "../../Utils"; import { CollectionDockingView } from "../views/collections/CollectionDockingView"; @@ -43,8 +43,8 @@ export async function DragLinksAsDocuments(dragEle: HTMLElement, x: number, y: n let draggedDocs: Doc[] = []; let draggedFromDocs: Doc[] = [] if (srcTarg) { - let linkToDocs = await DocListCast(srcTarg.linkedToDocs); - let linkFromDocs = await DocListCast(srcTarg.linkedFromDocs); + let linkToDocs = await DocListCastAsync(srcTarg.linkedToDocs); + let linkFromDocs = await DocListCastAsync(srcTarg.linkedFromDocs); if (linkToDocs) draggedDocs = linkToDocs.map(linkDoc => Cast(linkDoc.linkedTo, Doc) as Doc); if (linkFromDocs) draggedFromDocs = linkFromDocs.map(linkDoc => Cast(linkDoc.linkedFrom, Doc) as Doc); } diff --git a/src/client/views/PresentationView.tsx b/src/client/views/PresentationView.tsx index 4853eb151..3fb24a339 100644 --- a/src/client/views/PresentationView.tsx +++ b/src/client/views/PresentationView.tsx @@ -141,8 +141,15 @@ export class PresentationView extends React.Component { (activeW) => { if (activeW && activeW instanceof Doc) { PromiseValue(Cast(activeW.presentationView, Doc)). - then(pv => runInAction(() => - self.Document = pv ? pv : (activeW.presentationView = new Doc()))) + then(pv => runInAction(() => { + if (pv) self.Document = pv; + else { + pv = new Doc(); + pv.title = "Presentation Doc"; + activeW.presentationView = pv; + self.Document = pv; + } + })) } }, { fireImmediately: true }); diff --git a/src/client/views/Templates.tsx b/src/client/views/Templates.tsx index bbedc95f1..a98870b04 100644 --- a/src/client/views/Templates.tsx +++ b/src/client/views/Templates.tsx @@ -5,6 +5,7 @@ export enum TemplatePosition { InnerBottom, InnerRight, InnerLeft, + TopRight, OutterTop, OutterBottom, OutterRight, @@ -39,30 +40,42 @@ export namespace Templates { // export const BasicLayout = new Template("Basic layout", "{layout}"); export const Caption = new Template("Caption", TemplatePosition.OutterBottom, - `
` - ); + `
+ +
` ); + export const TitleOverlay = new Template("TitleOverlay", TemplatePosition.InnerTop, - `
{layout}
-
- {props.Document.title} -
` - ); + `
+
{layout}
+
+ {props.Document.title} +
+
` ); + export const Title = new Template("Title", TemplatePosition.InnerTop, `
{layout}
{props.Document.title} -
` - ); +
` ); export const Bullet = new Template("Bullet", TemplatePosition.InnerTop, `
{layout}
-
- +
` ); + export function ImageOverlay(width: number, height: number, field: string = "thumbnail") { + return (`
+
{layout}
+
+ +
+
`); + } + export const TemplateList: Template[] = [Title, TitleOverlay, Caption, Bullet]; export function sortTemplates(a: Template, b: Template) { diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx index 2b1f7bb37..645296d27 100644 --- a/src/client/views/collections/CollectionBaseView.tsx +++ b/src/client/views/collections/CollectionBaseView.tsx @@ -4,7 +4,7 @@ import * as React from 'react'; import { ContextMenu } from '../ContextMenu'; import { FieldViewProps } from '../nodes/FieldView'; import { Cast, FieldValue, PromiseValue, NumCast } from '../../../new_fields/Types'; -import { Doc, FieldResult, Opt } from '../../../new_fields/Doc'; +import { Doc, FieldResult, Opt, DocListCast } from '../../../new_fields/Doc'; import { listSpec } from '../../../new_fields/Schema'; import { List } from '../../../new_fields/List'; import { Id } from '../../../new_fields/RefField'; @@ -63,13 +63,13 @@ export class CollectionBaseView extends React.Component { if (!(documentToAdd instanceof Doc)) { return false; } - let data = Cast(documentToAdd.data, listSpec(Doc), []).filter(d => d).map(d => d as Doc); - for (const doc of data.filter(d => d instanceof Document)) { + let data = DocListCast(documentToAdd.data); + for (const doc of data) { if (this.createsCycle(doc, containerDocument)) { return true; } } - let annots = Cast(documentToAdd.annotations, listSpec(Doc), []).filter(d => d).map(d => d as Doc); + let annots = DocListCast(documentToAdd.annotations); for (const annot of annots) { if (this.createsCycle(annot, containerDocument)) { return true; diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index ae949b2ed..506e60a65 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -19,7 +19,7 @@ import { DocumentView } from "../nodes/DocumentView"; import { FieldView, FieldViewProps } from "../nodes/FieldView"; import "./CollectionSchemaView.scss"; import { CollectionSubView } from "./CollectionSubView"; -import { Opt, Field, Doc, DocListCast } from "../../../new_fields/Doc"; +import { Opt, Field, Doc, DocListCastAsync, DocListCast } from "../../../new_fields/Doc"; import { Cast, FieldValue, NumCast } from "../../../new_fields/Types"; import { listSpec } from "../../../new_fields/Schema"; import { List } from "../../../new_fields/List"; @@ -118,7 +118,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { } const run = script.run; //TODO This should be able to be refactored to compile the script once - const val = await DocListCast(this.props.Document[this.props.fieldKey]) + const val = await DocListCastAsync(this.props.Document[this.props.fieldKey]) val && val.forEach(doc => applyToDoc(doc, run)); }}> @@ -276,7 +276,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { } get documentKeysCheckList() { - const docs = Cast(this.props.Document[this.props.fieldKey], listSpec(Doc), []).filter(d => d).map(d => d as Doc); + const docs = DocListCast(this.props.Document[this.props.fieldKey]); let keys: { [key: string]: boolean } = {}; // bcz: ugh. this is untracked since otherwise a large collection of documents will blast the server for all their fields. // then as each document's fields come back, we update the documents _proxies. Each time we do this, the whole schema will be diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 0b08e150a..a86d250bd 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -10,7 +10,7 @@ import * as rp from 'request-promise'; import { CollectionView } from "./CollectionView"; import { CollectionPDFView } from "./CollectionPDFView"; import { CollectionVideoView } from "./CollectionVideoView"; -import { Doc, Opt, FieldResult } from "../../../new_fields/Doc"; +import { Doc, Opt, FieldResult, DocListCast } from "../../../new_fields/Doc"; import { DocComponent } from "../DocComponent"; import { listSpec } from "../../../new_fields/Schema"; import { Cast, PromiseValue, FieldValue, ListSpec } from "../../../new_fields/Types"; @@ -49,7 +49,7 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T) { get children() { //TODO tfs: This might not be what we want? //This linter error can't be fixed because of how js arguments work, so don't switch this to filter(FieldValue) - return Cast(this.props.Document[this.props.fieldKey], listSpec(Doc), []).filter(doc => FieldValue(doc)).map(doc => doc as Doc); + return DocListCast(this.props.Document[this.props.fieldKey]); } @action diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 33787f06b..78c84cc89 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -18,9 +18,7 @@ import { Main } from '../Main'; import { CurrentUserUtils } from '../../../server/authentication/models/current_user_utils'; import { CollectionDockingView } from './CollectionDockingView'; import { DocumentManager } from '../../util/DocumentManager'; -import { Utils } from '../../../Utils'; import { List } from '../../../new_fields/List'; -import { indexOf } from 'typescript-collections/dist/lib/arrays'; export interface TreeViewProps { @@ -155,16 +153,21 @@ class TreeView extends React.Component { let keys = Array.from(Object.keys(this.props.document)); if (this.props.document.proto instanceof Doc) { keys.push(...Array.from(Object.keys(this.props.document.proto))); + while (keys.indexOf("proto") !== -1) keys.splice(keys.indexOf("proto"), 1); } keys.map(key => { - let docList = Cast(this.props.document[key], listSpec(Doc)); - if (docList instanceof List && docList.length && docList[0] instanceof Doc) { + let docList = DocListCast(this.props.document[key]); + let doc = Cast(this.props.document[key], Doc); + if (doc instanceof Doc || docList.length) { if (!this._collapsed) { bulletType = BulletType.Collapsible; + let spacing = (key === "data") ? 0 : -10; contentElement.push(
    {(key === "data") ? (null) : - {key}} - {TreeView.GetChildElements(docList, key !== "data", (doc: Doc) => this.remove(doc, key), this.move, this.props.dropAction)} + {key}} +
    + {TreeView.GetChildElements(doc instanceof Doc ? [doc] : docList, key !== "data", (doc: Doc) => this.remove(doc, key), this.move, this.props.dropAction)} +
); } else bulletType = BulletType.Collapsed; @@ -179,7 +182,7 @@ class TreeView extends React.Component {
; } - public static GetChildElements(docs: (Doc | Promise)[], allowMinimized: boolean, remove: ((doc: Doc) => void), move: DragManager.MoveFunction, dropAction: dropActionType) { + public static GetChildElements(docs: Doc[], allowMinimized: boolean, remove: ((doc: Doc) => void), move: DragManager.MoveFunction, dropAction: dropActionType) { return docs.filter(child => child instanceof Doc && !child.excludeFromLibrary && (allowMinimized || !child.isMinimized)).filter(doc => FieldValue(doc)).map(child => ); } @@ -203,12 +206,11 @@ export class CollectionTreeView extends CollectionSubView(Document) { } } render() { - const children = this.children; let dropAction = StrCast(this.props.Document.dropAction, "alias") as dropActionType; - if (!children) { + if (!this.children) { return (null); } - let childElements = TreeView.GetChildElements(children, false, this.remove, this.props.moveDocument, dropAction); + let childElements = TreeView.GetChildElements(this.children, false, this.remove, this.props.moveDocument, dropAction); return (
{ - let doclist = Cast(this.props.Document[this.props.fieldKey], listSpec(Doc), []); - return { doclist: doclist ? doclist : [], xs: doclist instanceof List ? doclist.map(d => d instanceof Doc && d.x) : [] }; + let doclist = DocListCast(this.props.Document[this.props.fieldKey]); + return { doclist: doclist ? doclist : [], xs: doclist.map(d => d.x) }; }, - async () => { - let doclist = await DocListCast(this.props.Document[this.props.fieldKey]); + () => { + let doclist = DocListCast(this.props.Document[this.props.fieldKey]); let views = doclist ? doclist.filter(doc => StrCast(doc.backgroundLayout).indexOf("istogram") !== -1) : []; views.forEach((dstDoc, i) => { views.forEach((srcDoc, j) => { @@ -84,7 +84,7 @@ export class CollectionFreeFormLinksView extends React.Component d).map(d => d as Doc). + DocListCast(this.props.Document[this.props.fieldKey]). filter(child => child[Id] === collid).map(view => DocumentManager.Instance.getDocumentViews(view).map(view => diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 1bf39e335..9ace0272a 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -1,3 +1,4 @@ +import * as htmlToImage from "html-to-image"; import { action, computed, observable } from "mobx"; import { observer } from "mobx-react"; import { Docs } from "../../../documents/Documents"; @@ -14,6 +15,8 @@ import { Doc } from "../../../../new_fields/Doc"; import { NumCast, Cast } from "../../../../new_fields/Types"; import { InkField, StrokeData } from "../../../../new_fields/InkField"; import { List } from "../../../../new_fields/List"; +import { ImageField } from "../../../../new_fields/URLField"; +import { Template, Templates } from "../../Templates"; interface MarqueeViewProps { getContainerTransform: () => Transform; @@ -30,6 +33,7 @@ interface MarqueeViewProps { @observer export class MarqueeView extends React.Component { + private _mainCont = React.createRef(); @observable _lastX: number = 0; @observable _lastY: number = 0; @observable _downX: number = 0; @@ -166,7 +170,7 @@ export class MarqueeView extends React.Component @undoBatch @action - marqueeCommand = (e: KeyboardEvent) => { + marqueeCommand = async (e: KeyboardEvent) => { if (this._commandExecuted) { return; } @@ -224,13 +228,17 @@ export class MarqueeView extends React.Component let scrpt = this.props.getTransform().inverse().transformPoint(bounds.left, bounds.top); let summary = Docs.TextDocument({ x: bounds.left, y: bounds.top, width: 300, height: 100, backgroundColor: "yellow", title: "-summary-" }); + let dataUrl = await htmlToImage.toPng(this._mainCont.current!, { width: bounds.width, height: bounds.height, quality: 1 }); + summary.proto!.thumbnail = new ImageField(new URL(dataUrl)); + + summary.proto!.templates = new List([Templates.ImageOverlay(Math.min(50, bounds.width), bounds.height * Math.min(50, bounds.width) / bounds.width, "thumbnail")]); if (e.key === "s" || e.key === "p") { summary.proto!.maximizeOnRight = true; newCollection.proto!.summaryDoc = summary; selected = [newCollection]; } summary.proto!.summarizedDocs = new List(selected); - summary.proto!.isButton = true; + //summary.proto!.isButton = true; selected.map(summarizedDoc => { let maxx = NumCast(summarizedDoc.x, undefined); let maxy = NumCast(summarizedDoc.y, undefined); @@ -313,17 +321,21 @@ export class MarqueeView extends React.Component @computed get marqueeDiv() { - let p = this.props.getContainerTransform().transformPoint(this._downX < this._lastX ? this._downX : this._lastX, this._downY < this._lastY ? this._downY : this._lastY); let v = this.props.getContainerTransform().transformDirection(this._lastX - this._downX, this._lastY - this._downY); - return
+ return
; } render() { + let p = this.props.getContainerTransform().transformPoint(this._downX < this._lastX ? this._downX : this._lastX, this._downY < this._lastY ? this._downY : this._lastY); return
- {this.props.children} - {!this._visible ? (null) : this.marqueeDiv} +
+
+ {this.props.children} +
+ {!this._visible ? null : this.marqueeDiv} +
; } } \ No newline at end of file diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index b05f2eea2..39d216da0 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -9,10 +9,10 @@ import { createSchema, makeInterface, listSpec } from "../../../new_fields/Schem import { FieldValue, Cast, NumCast, BoolCast, StrCast } from "../../../new_fields/Types"; import { OmitKeys, Utils } from "../../../Utils"; import { SelectionManager } from "../../util/SelectionManager"; -import { Doc, DocListCast, HeightSym } from "../../../new_fields/Doc"; +import { Doc, DocListCastAsync, DocListCast, } from "../../../new_fields/Doc"; import { List } from "../../../new_fields/List"; import { CollectionDockingView } from "../collections/CollectionDockingView"; -import { undoBatch, UndoManager } from "../../util/UndoManager"; +import { UndoManager } from "../../util/UndoManager"; export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps { } @@ -65,7 +65,7 @@ export class CollectionFreeFormDocumentView extends DocComponent this.nativeWidth > 0 ? this.width / this.nativeWidth : 1; panelWidth = () => this.props.PanelWidth(); panelHeight = () => this.props.PanelHeight(); - toggleMinimized = async () => this.toggleIcon(await DocListCast(this.props.Document.maximizedDocs)); + toggleMinimized = async () => this.toggleIcon(await DocListCastAsync(this.props.Document.maximizedDocs)); getTransform = (): Transform => this.props.ScreenToLocalTransform() .translate(-this.X, -this.Y) .scale(1 / this.contentScaling()).scale(1 / this.zoom) @@ -132,7 +132,7 @@ export class CollectionFreeFormDocumentView extends DocComponent { + expandedDocs.forEach(maxDoc => { maxDoc.isMinimized = false; if (!dataDocs || dataDocs.indexOf(maxDoc) == -1) { CollectionDockingView.Instance.AddRightSplit(maxDoc); @@ -195,8 +197,8 @@ export class CollectionFreeFormDocumentView extends DocComponent this.props.addDocument!(await maxDoc, false)); - this.toggleIcon(maximizedDocs); + this.props.addDocument && expandedDocs.forEach(async maxDoc => this.props.addDocument!(await maxDoc, false)); + this.toggleIcon(expandedDocs); } } } diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 5aa74c703..90f67db7c 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -12,13 +12,13 @@ import { CollectionPDFView } from "../collections/CollectionPDFView"; import { CollectionVideoView } from "../collections/CollectionVideoView"; import { CollectionView } from "../collections/CollectionView"; import { ContextMenu } from "../ContextMenu"; -import { Template, Templates } from "./../Templates"; +import { Template } from "./../Templates"; import { DocumentContentsView } from "./DocumentContentsView"; import "./DocumentView.scss"; import React = require("react"); -import { Opt, Doc, WidthSym, HeightSym, DocListCast } from "../../../new_fields/Doc"; +import { Opt, Doc, WidthSym, HeightSym, DocListCastAsync, DocListCast } from "../../../new_fields/Doc"; import { DocComponent } from "../DocComponent"; -import { createSchema, makeInterface, listSpec } from "../../../new_fields/Schema"; +import { createSchema, makeInterface } from "../../../new_fields/Schema"; import { FieldValue, StrCast, BoolCast, Cast } from "../../../new_fields/Types"; import { List } from "../../../new_fields/List"; import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView"; @@ -109,8 +109,8 @@ export class DocumentView extends DocComponent(Docu } // bcz: kind of ugly .. setup a reaction to update the title of a summary document's target (maximizedDocs) whenver the summary doc's title changes this._reactionDisposer = reaction(() => [this.props.Document.maximizedDocs, this.props.Document.summaryDoc, this.props.Document.summaryDoc instanceof Doc ? this.props.Document.summaryDoc.title : ""], - async () => { - let maxDoc = await DocListCast(this.props.Document.maximizedDocs); + () => { + let maxDoc = DocListCast(this.props.Document.maximizedDocs); if (maxDoc && StrCast(this.props.Document.layout).indexOf("IconBox") !== -1) { this.props.Document.title = (maxDoc && maxDoc.length === 1 ? maxDoc[0].title + ".icon" : ""); } @@ -145,7 +145,7 @@ export class DocumentView extends DocComponent(Docu startDragging(x: number, y: number, dropAction: dropActionType, dragSubBullets: boolean) { if (this._mainCont.current) { - let allConnected = dragSubBullets ? [this.props.Document, ...Cast(this.props.Document.subBulletDocs, listSpec(Doc), []).filter(d => d).map(d => d as Doc)] : [this.props.Document]; + let allConnected = [this.props.Document, ...(dragSubBullets ? DocListCast(this.props.Document.subBulletDocs) : [])]; const [left, top] = this.props.ScreenToLocalTransform().scale(this.props.ContentScaling()).inverse().transformPoint(0, 0); let dragData = new DragManager.DocumentDragData(allConnected); const [xoff, yoff] = this.props.ScreenToLocalTransform().scale(this.props.ContentScaling()).transformDirection(x - left, y - top); @@ -169,17 +169,17 @@ export class DocumentView extends DocComponent(Docu SelectionManager.SelectDoc(this, e.ctrlKey); } } - _hitIsBullet = false; + _hitExpander = false; onPointerDown = (e: React.PointerEvent): void => { this._downX = e.clientX; this._downY = e.clientY; if (CollectionFreeFormView.RIGHT_BTN_DRAG && (e.button === 2 || (e.button === 0 && e.altKey)) && !this.isSelected()) { return; } - this._hitIsBullet = (e.target && (e.target as any).id === "isBullet") || Cast(this.props.Document.subBulletDocs, listSpec(Doc), []).filter(d => d).map(d => d as Doc).length > 0; + this._hitExpander = DocListCast(this.props.Document.subBulletDocs).length > 0; if (e.shiftKey && e.buttons === 1) { if (this.props.isTopMost) { - this.startDragging(e.pageX, e.pageY, e.altKey || e.ctrlKey ? "alias" : undefined, this._hitIsBullet); + this.startDragging(e.pageX, e.pageY, e.altKey || e.ctrlKey ? "alias" : undefined, this._hitExpander); } else if (this.props.Document) { CollectionDockingView.Instance.StartOtherDrag([Doc.MakeAlias(this.props.Document)], e); } @@ -197,7 +197,7 @@ export class DocumentView extends DocComponent(Docu document.removeEventListener("pointermove", this.onPointerMove); document.removeEventListener("pointerup", this.onPointerUp); if (!e.altKey && !this.topMost && (!CollectionFreeFormView.RIGHT_BTN_DRAG && e.buttons === 1) || (CollectionFreeFormView.RIGHT_BTN_DRAG && e.buttons === 2)) { - this.startDragging(this._downX, this._downY, e.ctrlKey || e.altKey ? "alias" : undefined, this._hitIsBullet); + this.startDragging(this._downX, this._downY, e.ctrlKey || e.altKey ? "alias" : undefined, this._hitExpander); } } e.stopPropagation(); // doesn't actually stop propagation since all our listeners are listening to events on 'document' however it does mark the event as cancelBubble=true which we test for in the move event handlers @@ -232,6 +232,7 @@ export class DocumentView extends DocComponent(Docu ContextMenu.Instance.clearItems(); SelectionManager.DeselectAll(); } + @undoBatch @action drop = async (e: Event, de: DragManager.DropEvent) => { @@ -259,7 +260,6 @@ export class DocumentView extends DocComponent(Docu } } - @action addTemplate = (template: Template) => { this.templates.push(template.Layout); @@ -307,7 +307,6 @@ export class DocumentView extends DocComponent(Docu } } - isSelected = () => SelectionManager.IsSelected(this); select = (ctrlPressed: boolean) => SelectionManager.SelectDoc(this, ctrlPressed); diff --git a/src/client/views/nodes/IconBox.tsx b/src/client/views/nodes/IconBox.tsx index 4bcb4c636..48aecdcd0 100644 --- a/src/client/views/nodes/IconBox.tsx +++ b/src/client/views/nodes/IconBox.tsx @@ -2,12 +2,12 @@ import React = require("react"); import { library } from '@fortawesome/fontawesome-svg-core'; import { faCaretUp, faFilePdf, faFilm, faImage, faObjectGroup, faStickyNote } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { computed, observable, runInAction, reaction, IReactionDisposer } from "mobx"; +import { computed, observable, runInAction } from "mobx"; import { observer } from "mobx-react"; import { FieldView, FieldViewProps } from './FieldView'; import "./IconBox.scss"; import { Cast, StrCast, BoolCast } from "../../../new_fields/Types"; -import { Doc, DocListCast } from "../../../new_fields/Doc"; +import { Doc } from "../../../new_fields/Doc"; import { IconField } from "../../../new_fields/IconField"; import { ContextMenu } from "../ContextMenu"; import Measure from "react-measure"; diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 0e9e904a8..f9659a4b2 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -1,5 +1,5 @@ -import { action, observable } from 'mobx'; +import { action, observable, trace } from 'mobx'; import { observer } from "mobx-react"; import Lightbox from 'react-image-lightbox'; import 'react-image-lightbox/style.css'; // This only needs to be imported once in your app @@ -157,15 +157,21 @@ export class ImageBox extends DocComponent(ImageD } render() { + trace(); let field = this.Document[this.props.fieldKey]; let paths: string[] = ["http://www.cs.brown.edu/~bcz/face.gif"]; if (field instanceof ImageField) paths = [field.url.href]; else if (field instanceof List) paths = field.filter(val => val instanceof ImageField).map(p => (p as ImageField).url.href); - let nativeWidth = FieldValue(this.Document.nativeWidth, 1); + let nativeWidth = FieldValue(this.Document.nativeWidth, (this.props.PanelWidth as any) as string ? Number((this.props.PanelWidth as any) as string) : 50); let interactive = InkingControl.Instance.selectedTool ? "" : "-interactive"; + let id = this.props.id; return ( -
- Image not found +
+ {paths.length > 1 ? this.dots(paths) : (null)} {this.lightbox(paths)}
); diff --git a/src/client/views/nodes/LinkMenu.tsx b/src/client/views/nodes/LinkMenu.tsx index 24901913d..7bf13d5f9 100644 --- a/src/client/views/nodes/LinkMenu.tsx +++ b/src/client/views/nodes/LinkMenu.tsx @@ -5,7 +5,7 @@ import { LinkBox } from "./LinkBox"; import { LinkEditor } from "./LinkEditor"; import './LinkMenu.scss'; import React = require("react"); -import { Doc } from "../../../new_fields/Doc"; +import { Doc, DocListCast } from "../../../new_fields/Doc"; import { Cast, FieldValue } from "../../../new_fields/Types"; import { listSpec } from "../../../new_fields/Schema"; import { Id } from "../../../new_fields/RefField"; @@ -31,8 +31,8 @@ export class LinkMenu extends React.Component { render() { //get list of links from document - let linkFrom = Cast(this.props.docView.props.Document.linkedFromDocs, listSpec(Doc), []).filter(d => d).map(d => d as Doc); - let linkTo = Cast(this.props.docView.props.Document.linkedToDocs, listSpec(Doc), []).filter(d => d).map(d => d as Doc); + let linkFrom = DocListCast(this.props.docView.props.Document.linkedFromDocs); + let linkTo = DocListCast(this.props.docView.props.Document.linkedToDoc); if (this._editingLink === undefined) { return (
diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 2ab145fa3..46ccb3e90 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -29,13 +29,17 @@ export const SelfProxy = Symbol("SelfProxy"); export const WidthSym = Symbol("Width"); export const HeightSym = Symbol("Height"); -export function DocListCast(field: FieldResult): Promise; -export function DocListCast(field: FieldResult, defaultValue: Doc[]): Promise; -export function DocListCast(field: FieldResult, defaultValue?: Doc[]) { +export function DocListCastAsync(field: FieldResult): Promise; +export function DocListCastAsync(field: FieldResult, defaultValue: Doc[]): Promise; +export function DocListCastAsync(field: FieldResult, defaultValue?: Doc[]) { const list = Cast(field, listSpec(Doc)); return list ? Promise.all(list) : Promise.resolve(defaultValue); } +export function DocListCast(field: FieldResult) { + return Cast(field, listSpec(Doc), []).filter(d => d && d instanceof Doc).map(d => d as Doc) +} + @Deserializable("doc").withFields(["id"]) export class Doc extends RefField { constructor(id?: FieldId, forceSave?: boolean) { -- cgit v1.2.3-70-g09d2 From 281bfa589bd1ca66823003ca91cc11ce895fe5e2 Mon Sep 17 00:00:00 2001 From: bob Date: Tue, 14 May 2019 18:59:32 -0400 Subject: fixes for northstar --- src/client/documents/Documents.ts | 9 ++- src/client/northstar/dash-fields/HistogramField.ts | 11 ++-- .../dash-nodes/HistogramBinPrimitiveCollection.ts | 4 +- src/client/northstar/dash-nodes/HistogramBox.tsx | 16 +++--- .../dash-nodes/HistogramBoxPrimitives.tsx | 3 - src/client/northstar/manager/Gateway.ts | 12 ++++ src/client/northstar/model/ModelHelpers.ts | 10 +++- src/client/northstar/model/idea/idea.ts | 6 ++ src/client/northstar/operations/BaseOperation.ts | 17 ------ .../northstar/operations/HistogramOperation.ts | 12 ++-- src/client/views/Main.tsx | 54 +----------------- .../views/collections/CollectionSchemaView.tsx | 39 ++++++++++++- .../collections/collectionFreeForm/MarqueeView.tsx | 7 ++- src/client/views/nodes/DocumentView.tsx | 2 +- .../authentication/models/current_user_utils.ts | 65 ++++++++++++++++++++-- 15 files changed, 162 insertions(+), 105 deletions(-) (limited to 'src/client/northstar') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 11929455c..ed260d42e 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -33,6 +33,7 @@ import { DocServer } from "../DocServer"; import { StrokeData, InkField } from "../../new_fields/InkField"; import { dropActionType } from "../util/DragManager"; import { DateField } from "../../new_fields/DateField"; +import { schema } from "prosemirror-schema-basic"; export interface DocumentOptions { x?: number; @@ -207,16 +208,18 @@ export namespace Docs { export function PdfDocument(url: string, options: DocumentOptions = {}) { return CreateInstance(pdfProto, new PdfField(new URL(url)), options); } + export async function DBDocument(url: string, options: DocumentOptions = {}) { let schemaName = options.title ? options.title : "-no schema-"; let ctlog = await Gateway.Instance.GetSchema(url, schemaName); if (ctlog && ctlog.schemas) { let schema = ctlog.schemas[0]; let schemaDoc = Docs.TreeDocument([], { ...options, nativeWidth: undefined, nativeHeight: undefined, width: 150, height: 100, title: schema.displayName! }); - let schemaDocuments = Cast(schemaDoc.data, listSpec(Doc)); + let schemaDocuments = Cast(schemaDoc.data, listSpec(Doc), []); if (!schemaDocuments) { return; } + CurrentUserUtils.AddNorthstarSchema(schema, schemaDoc); const docs = schemaDocuments; CurrentUserUtils.GetAllNorthstarColumnAttributes(schema).map(attr => { DocServer.GetRefField(attr.displayName! + ".alias").then(action((field: Opt) => { @@ -251,8 +254,8 @@ export namespace Docs { } return CreateInstance(collProto, new List(documents), { schemaColumns: new List(["title"]), ...options, viewType: CollectionViewType.Freeform }); } - export function SchemaDocument(documents: Array, options: DocumentOptions) { - return CreateInstance(collProto, new List(documents), { schemaColumns: new List(["title"]), ...options, viewType: CollectionViewType.Schema }); + export function SchemaDocument(schemaColumns: string[], documents: Array, options: DocumentOptions) { + return CreateInstance(collProto, new List(documents), { schemaColumns: new List(schemaColumns), ...options, viewType: CollectionViewType.Schema }); } export function TreeDocument(documents: Array, options: DocumentOptions) { return CreateInstance(collProto, new List(documents), { schemaColumns: new List(["title"]), ...options, viewType: CollectionViewType.Tree }); diff --git a/src/client/northstar/dash-fields/HistogramField.ts b/src/client/northstar/dash-fields/HistogramField.ts index f01f08487..aabc77bb2 100644 --- a/src/client/northstar/dash-fields/HistogramField.ts +++ b/src/client/northstar/dash-fields/HistogramField.ts @@ -9,7 +9,8 @@ import { OmitKeys } from "../../../Utils"; import { Deserializable } from "../../util/SerializationHelper"; function serialize(field: HistogramField) { - return OmitKeys(field.HistoOp, ['Links', 'BrushLinks', 'Result', 'BrushColors', 'FilterModels', 'FilterOperand']).omit; + let obj = OmitKeys(field, ['Links', 'BrushLinks', 'Result', 'BrushColors', 'FilterModels', 'FilterOperand']).omit; + return obj; } function deserialize(jp: any) { @@ -31,10 +32,10 @@ function deserialize(jp: any) { } }); if (X && Y && V) { - return new HistogramField(new HistogramOperation(jp.SchemaName, X, Y, V, jp.Normalization)); + return new HistogramOperation(jp.SchemaName, X, Y, V, jp.Normalization); } } - return new HistogramField(HistogramOperation.Empty); + return HistogramOperation.Empty; } @Deserializable("histogramField") @@ -50,6 +51,8 @@ export class HistogramField extends ObjectField { } [Copy]() { - return new HistogramField(this.HistoOp.Copy()); + let y = this.HistoOp; + let z = this.HistoOp["Copy"]; + return new HistogramField(HistogramOperation.Duplicate(this.HistoOp)); } } \ No newline at end of file diff --git a/src/client/northstar/dash-nodes/HistogramBinPrimitiveCollection.ts b/src/client/northstar/dash-nodes/HistogramBinPrimitiveCollection.ts index 6291ec1fc..3e9145a1b 100644 --- a/src/client/northstar/dash-nodes/HistogramBinPrimitiveCollection.ts +++ b/src/client/northstar/dash-nodes/HistogramBinPrimitiveCollection.ts @@ -198,8 +198,8 @@ export class HistogramBinPrimitiveCollection { 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!; + let aggResult = ModelHelpers.GetAggregateResult(bin, marginAggregateKey); + return aggResult instanceof MarginAggregateResult && aggResult.absolutMargin ? aggResult.absolutMargin : 0; } private createBinPrimitive(barAxis: number, brush: Brush, marginRect: PIXIRectangle, diff --git a/src/client/northstar/dash-nodes/HistogramBox.tsx b/src/client/northstar/dash-nodes/HistogramBox.tsx index ed556cf45..eb1ad69b7 100644 --- a/src/client/northstar/dash-nodes/HistogramBox.tsx +++ b/src/client/northstar/dash-nodes/HistogramBox.tsx @@ -17,9 +17,8 @@ import "./HistogramBox.scss"; import { HistogramBoxPrimitives } from './HistogramBoxPrimitives'; import { HistogramLabelPrimitives } from "./HistogramLabelPrimitives"; import { StyleConstants } from "../utils/StyleContants"; -import { NumCast, Cast } from "../../../new_fields/Types"; -import { listSpec } from "../../../new_fields/Schema"; -import { Doc, DocListCast } from "../../../new_fields/Doc"; +import { Cast } from "../../../new_fields/Types"; +import { Doc, DocListCast, DocListCastAsync } from "../../../new_fields/Doc"; import { Id } from "../../../new_fields/RefField"; @@ -119,15 +118,16 @@ export class HistogramBox extends React.Component { if (this.HistoOp !== HistogramOperation.Empty) { reaction(() => DocListCast(this.props.Document.linkedFromDocs), (docs) => this.HistoOp.Links.splice(0, this.HistoOp.Links.length, ...docs), { fireImmediately: true }); reaction(() => DocListCast(this.props.Document.brushingDocs).length, - () => { - let brushingDocs = DocListCast(this.props.Document.brushingDocs); + async () => { + let brushingDocs = await DocListCastAsync(this.props.Document.brushingDocs); const proto = this.props.Document.proto; - if (proto) { - this.HistoOp.BrushLinks.splice(0, this.HistoOp.BrushLinks.length, ...brushingDocs.map((brush, i) => { + if (proto && brushingDocs) { + let mapped = brushingDocs.map((brush, i) => { brush.backgroundColor = StyleConstants.BRUSH_COLORS[i % StyleConstants.BRUSH_COLORS.length]; let brushed = DocListCast(brush.brushingDocs); return { l: brush, b: brushed[0][Id] === proto[Id] ? brushed[1] : brushed[0] }; - })); + }); + this.HistoOp.BrushLinks.splice(0, this.HistoOp.BrushLinks.length, ...mapped); } }, { 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 721bf6a89..350987695 100644 --- a/src/client/northstar/dash-nodes/HistogramBoxPrimitives.tsx +++ b/src/client/northstar/dash-nodes/HistogramBoxPrimitives.tsx @@ -11,9 +11,6 @@ import { StyleConstants } from "../../northstar/utils/StyleContants"; import { HistogramBinPrimitiveCollection, HistogramBinPrimitive } from "./HistogramBinPrimitiveCollection"; import { HistogramBox } from "./HistogramBox"; import "./HistogramBoxPrimitives.scss"; -import { JSXElement } from "babel-types"; -import { Utils } from "../utils/Utils"; -import { all } from "bluebird"; export interface HistogramPrimitivesProps { HistoBox: HistogramBox; diff --git a/src/client/northstar/manager/Gateway.ts b/src/client/northstar/manager/Gateway.ts index d26f2724f..c541cce6a 100644 --- a/src/client/northstar/manager/Gateway.ts +++ b/src/client/northstar/manager/Gateway.ts @@ -23,6 +23,18 @@ export class Gateway { } } + public async PostSchema(csvdata: string, schemaname: string): Promise { + try { + const json = await this.MakePostJsonRequest("postSchema", { csv: csvdata, schema: schemaname }); + // const cat = Catalog.fromJS(json); + // return cat; + return json; + } + catch (error) { + throw new Error("can not reach northstar's backend"); + } + } + public async GetSchema(pathname: string, schemaname: string): Promise { try { const json = await this.MakeGetRequest("schema", undefined, { path: pathname, schema: schemaname }); diff --git a/src/client/northstar/model/ModelHelpers.ts b/src/client/northstar/model/ModelHelpers.ts index ac807b41f..80bb71224 100644 --- a/src/client/northstar/model/ModelHelpers.ts +++ b/src/client/northstar/model/ModelHelpers.ts @@ -31,7 +31,15 @@ export class ModelHelpers { } public static GetAggregateParametersIndex(histogramResult: HistogramResult, aggParameters?: AggregateParameters): number { - return ArrayUtil.IndexOfWithEqual(histogramResult.aggregateParameters!, aggParameters); + return Array.from(histogramResult.aggregateParameters!).findIndex((value, i, set) => { + if (set[i] instanceof CountAggregateParameters && value instanceof CountAggregateParameters) + return true; + if (set[i] instanceof MarginAggregateParameters && value instanceof MarginAggregateParameters) + return true; + if (set[i] instanceof SumAggregateParameters && value instanceof SumAggregateParameters) + return true; + return false; + }); } public static GetAggregateParameter(distinctAttributeParameters: AttributeParameters | undefined, atm: AttributeTransformationModel): AggregateParameters | undefined { diff --git a/src/client/northstar/model/idea/idea.ts b/src/client/northstar/model/idea/idea.ts index 9d9d60678..c73a822c7 100644 --- a/src/client/northstar/model/idea/idea.ts +++ b/src/client/northstar/model/idea/idea.ts @@ -22,6 +22,9 @@ export abstract class AggregateParameters implements IAggregateParameters { protected _discriminator: string; + public Equals(other: Object): boolean { + return this == other; + } constructor(data?: IAggregateParameters) { if (data) { for (var property in data) { @@ -204,6 +207,9 @@ export interface IAverageAggregateParameters extends ISingleDimensionAggregatePa export abstract class AttributeParameters implements IAttributeParameters { visualizationHints?: VisualizationHint[] | undefined; rawName?: string | undefined; + public Equals(other: Object): boolean { + return this == other; + } protected _discriminator: string; diff --git a/src/client/northstar/operations/BaseOperation.ts b/src/client/northstar/operations/BaseOperation.ts index c6d5f0a15..0d1361ebf 100644 --- a/src/client/northstar/operations/BaseOperation.ts +++ b/src/client/northstar/operations/BaseOperation.ts @@ -25,23 +25,6 @@ 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(" || ") + ")"; - // } - // 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 ""; } diff --git a/src/client/northstar/operations/HistogramOperation.ts b/src/client/northstar/operations/HistogramOperation.ts index 78b206bdc..74e23ea48 100644 --- a/src/client/northstar/operations/HistogramOperation.ts +++ b/src/client/northstar/operations/HistogramOperation.ts @@ -30,7 +30,7 @@ export class HistogramOperation extends BaseOperation implements IBaseFilterCons @observable public V: AttributeTransformationModel; @observable public SchemaName: string; @observable public QRange: QuantitativeBinRange | undefined; - @computed public get Schema() { return CurrentUserUtils.GetNorthstarSchema(this.SchemaName); } + public get Schema() { return CurrentUserUtils.GetNorthstarSchema(this.SchemaName); } constructor(schemaName: string, x: AttributeTransformationModel, y: AttributeTransformationModel, v: AttributeTransformationModel, normalized?: number) { super(); @@ -41,7 +41,11 @@ export class HistogramOperation extends BaseOperation implements IBaseFilterCons this.SchemaName = schemaName; } - Copy(): HistogramOperation { + public static Duplicate(op: HistogramOperation) { + + return new HistogramOperation(op.SchemaName, op.X, op.Y, op.V, op.Normalization); + } + public Copy(): HistogramOperation { return new HistogramOperation(this.SchemaName, this.X, this.Y, this.V, this.Normalization); } @@ -50,7 +54,7 @@ export class HistogramOperation extends BaseOperation implements IBaseFilterCons } - @computed public get FilterModels() { + public get FilterModels() { return this.BarFilterModels; } @action @@ -71,9 +75,7 @@ export class HistogramOperation extends BaseOperation implements IBaseFilterCons return FilterModel.GetFilterModelsRecursive(this, new Set(), filterModels, true); } - @computed public get BrushString(): string[] { - trace(); let brushes: string[] = []; this.BrushLinks.map(brushLink => { let brushHistogram = Cast(brushLink.b.data, HistogramField); diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index 66205f8ca..385fc6ead 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -12,13 +12,6 @@ import { CurrentUserUtils } from '../../server/authentication/models/current_use import { RouteStore } from '../../server/RouteStore'; import { emptyFunction, returnTrue, Utils, returnOne, returnZero } from '../../Utils'; import { Docs } from '../documents/Documents'; -import { ColumnAttributeModel } from '../northstar/core/attribute/AttributeModel'; -import { AttributeTransformationModel } from '../northstar/core/attribute/AttributeTransformationModel'; -import { Gateway, NorthstarSettings } from '../northstar/manager/Gateway'; -import { AggregateFunction, Catalog } from '../northstar/model/idea/idea'; -import '../northstar/model/ModelExtensions'; -import { HistogramOperation } from '../northstar/operations/HistogramOperation'; -import '../northstar/utils/Extensions'; import { SetupDrag, DragManager } from '../util/DragManager'; import { Transform } from '../util/Transform'; import { UndoManager } from '../util/UndoManager'; @@ -70,8 +63,6 @@ export class Main extends React.Component { } } - CurrentUserUtils.loadCurrentUser(); - library.add(faFont); library.add(faImage); library.add(faFilePdf); @@ -84,15 +75,8 @@ export class Main extends React.Component { library.add(faFilm); library.add(faMusic); library.add(faTree); - this.initEventListeners(); this.initAuthenticationRouters(); - - // try { - // this.initializeNorthstar(); - // } catch (e) { - - // } } componentDidMount() { window.onpopstate = this.onHistory; } @@ -155,7 +139,7 @@ export class Main extends React.Component { // bcz: strangely, we need a timeout to prevent exceptions/issues initializing GoldenLayout (the rendering engine for Main Container) setTimeout(() => { this.openWorkspace(mainDoc); - let pendingDocument = Docs.SchemaDocument([], { title: "New Mobile Uploads" }); + let pendingDocument = Docs.SchemaDocument(["title"], [], { title: "New Mobile Uploads" }); mainDoc.optionalRightCollection = pendingDocument; }, 0); } @@ -229,7 +213,7 @@ export class Main extends React.Component { let addTextNode = action(() => Docs.TextDocument({ borderRounding: -1, width: 200, height: 200, title: "a text note" })); let addColNode = action(() => Docs.FreeformDocument([], { width: 200, height: 200, title: "a freeform collection" })); - let addSchemaNode = action(() => Docs.SchemaDocument([], { width: 200, height: 200, title: "a schema collection" })); + let addSchemaNode = action(() => Docs.SchemaDocument(["title"], [], { width: 200, height: 200, title: "a schema collection" })); let addTreeNode = action(() => Docs.TreeDocument([CurrentUserUtils.UserDocument], { width: 250, height: 400, title: "Library:" + CurrentUserUtils.email, dropAction: "alias" })); // let addTreeNode = action(() => Docs.TreeDocument(this._northstarSchemas, { width: 250, height: 400, title: "northstar schemas", dropAction: "copy" })); let addVideoNode = action(() => Docs.VideoDocument(videourl, { width: 200, title: "video node" })); @@ -300,40 +284,6 @@ export class Main extends React.Component {
); } - - // --------------- Northstar hooks ------------- / - private _northstarSchemas: Doc[] = []; - - @action SetNorthstarCatalog(ctlog: Catalog) { - CurrentUserUtils.NorthstarDBCatalog = ctlog; - if (ctlog && ctlog.schemas) { - ctlog.schemas.map(schema => { - let schemaDocuments: Doc[] = []; - let attributesToBecomeDocs = CurrentUserUtils.GetAllNorthstarColumnAttributes(schema); - Promise.all(attributesToBecomeDocs.reduce((promises, attr) => { - promises.push(DocServer.GetRefField(attr.displayName! + ".alias").then(action((field: Opt) => { - if (field instanceof Doc) { - 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(Docs.HistogramDocument(histoOp, { width: 200, height: 200, title: attr.displayName! })); - } - }))); - return promises; - }, [] as Promise[])).finally(() => - this._northstarSchemas.push(Docs.TreeDocument(schemaDocuments, { width: 50, height: 100, title: schema.displayName! }))); - }); - } - } - async initializeNorthstar(): Promise { - const getEnvironment = await fetch("/assets/env.json", { redirect: "follow", method: "GET", credentials: "include" }); - NorthstarSettings.Instance.UpdateEnvironment(await getEnvironment.json()); - Gateway.Instance.ClearCatalog().then(async () => this.SetNorthstarCatalog(await Gateway.Instance.GetCatalog())); - } } (async () => { diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index 9ecccc559..f4ad5b357 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -20,11 +20,20 @@ import { FieldView, FieldViewProps } from "../nodes/FieldView"; import "./CollectionSchemaView.scss"; import { CollectionSubView } from "./CollectionSubView"; import { Opt, Field, Doc, DocListCastAsync, DocListCast } from "../../../new_fields/Doc"; -import { Cast, FieldValue, NumCast } from "../../../new_fields/Types"; +import { Cast, FieldValue, NumCast, StrCast } from "../../../new_fields/Types"; import { listSpec } from "../../../new_fields/Schema"; import { List } from "../../../new_fields/List"; import { Id } from "../../../new_fields/RefField"; import { isUndefined } from "typescript-collections/dist/lib/util"; +import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils"; +import { Gateway } from "../../northstar/manager/Gateway"; +import { DocServer } from "../../DocServer"; +import { ColumnAttributeModel } from "../../northstar/core/attribute/AttributeModel"; +import { HistogramOperation } from "../../northstar/operations/HistogramOperation"; +import { AggregateFunction } from "../../northstar/model/idea/idea"; +import { AttributeTransformationModel } from "../../northstar/core/attribute/AttributeTransformationModel"; +import { Docs } from "../../documents/Documents"; +import { ContextMenu } from "../ContextMenu"; // bcz: need to add drag and drop of rows and columns. This seems like it might work for rows: https://codesandbox.io/s/l94mn1q657 @@ -207,6 +216,32 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { } } + onContextMenu = (e: React.MouseEvent): void => { + if (!e.isPropagationStopped() && this.props.Document[Id] !== "mainDoc") { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 + ContextMenu.Instance.addItem({ description: "Make DB", event: this.makeDB }); + } + } + + @action + makeDB = async () => { + let csv: string = this.columns.reduce((val, col) => val + col + ",", ""); + csv = csv.substr(0, csv.length - 1) + "\n"; + let self = this; + DocListCast(this.props.Document.data).map(doc => { + csv += self.columns.reduce((val, col) => val + (doc[col] ? doc[col]!.toString() : "") + ",", ""); + csv = csv.substr(0, csv.length - 1) + "\n"; + }) + csv.substring(0, csv.length - 1); + let dbName = StrCast(this.props.Document.title); + let res = await Gateway.Instance.PostSchema(csv, dbName); + if (self.props.CollectionView.props.addDocument) { + let schemaDoc = await Docs.DBDocument("https://www.cs.brown.edu/" + dbName, { title: dbName }); + if (schemaDoc) { + self.props.CollectionView.props.addDocument(schemaDoc, false); + } + } + } + @action addColumn = () => { this.columns.push(this._newKeyName); @@ -325,7 +360,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { const children = this.children; return (
this.onDrop(e, {})} ref={this.createTarget}> + onDrop={(e: React.DragEvent) => this.onDrop(e, {})} onContextMenu={this.onContextMenu} ref={this.createTarget}>
({ diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 24dea200e..be7cddca6 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -17,6 +17,9 @@ import { InkField, StrokeData } from "../../../../new_fields/InkField"; import { List } from "../../../../new_fields/List"; import { ImageField } from "../../../../new_fields/URLField"; import { Template, Templates } from "../../Templates"; +import { Gateway } from "../../../northstar/manager/Gateway"; +import { DocServer } from "../../../DocServer"; +import { Id } from "../../../../new_fields/RefField"; interface MarqueeViewProps { getContainerTransform: () => Transform; @@ -111,8 +114,8 @@ export class MarqueeView extends React.Component doc.title = i.toString(); docList.push(doc); } - let newCol = Docs.SchemaDocument(docList, { x: x, y: y, title: "-dropped table-", width: 300, height: 100 }); - newCol.proto!.schemaColumns = new List([...(groupAttr ? ["_group"] : []), ...columns.filter(c => c)]); + let newCol = Docs.SchemaDocument([...(groupAttr ? ["_group"] : []), ...columns.filter(c => c)], docList, { x: x, y: y, title: "droppedTable", width: 300, height: 100 }); + this.props.addDocument(newCol, false); } })(); diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index b7ad9249a..c97bcbd94 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -306,7 +306,7 @@ export class DocumentView extends DocComponent(Docu cm.addItem({ description: "Find aliases", event: async () => { const aliases = await SearchUtil.GetAliasesOfDocument(this.props.Document); - CollectionDockingView.Instance.AddRightSplit(Docs.SchemaDocument(aliases, {})); + CollectionDockingView.Instance.AddRightSplit(Docs.SchemaDocument(["title"], aliases, {})); } }); cm.addItem({ description: "Copy URL", event: () => Utils.CopyText(DocServer.prepend("/doc/" + this.props.Document[Id])) }); diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index 5f45d7bcc..5b63ac356 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -1,15 +1,21 @@ import { computed, observable, action, runInAction } from "mobx"; import * as rp from 'request-promise'; import { Docs } from "../../../client/documents/Documents"; -import { Attribute, AttributeGroup, Catalog, Schema } from "../../../client/northstar/model/idea/idea"; +import { Attribute, AttributeGroup, Catalog, Schema, AggregateFunction } from "../../../client/northstar/model/idea/idea"; import { ArrayUtil } from "../../../client/northstar/utils/ArrayUtil"; import { RouteStore } from "../../RouteStore"; import { DocServer } from "../../../client/DocServer"; -import { Doc } from "../../../new_fields/Doc"; +import { Doc, Opt, Field } from "../../../new_fields/Doc"; import { List } from "../../../new_fields/List"; import { CollectionViewType } from "../../../client/views/collections/CollectionBaseView"; import { CollectionTreeView } from "../../../client/views/collections/CollectionTreeView"; import { CollectionView } from "../../../client/views/collections/CollectionView"; +import { NorthstarSettings, Gateway } from "../../../client/northstar/manager/Gateway"; +import { AttributeTransformationModel } from "../../../client/northstar/core/attribute/AttributeTransformationModel"; +import { ColumnAttributeModel } from "../../../client/northstar/core/attribute/AttributeModel"; +import { HistogramOperation } from "../../../client/northstar/operations/HistogramOperation"; +import { Cast, PromiseValue } from "../../../new_fields/Types"; +import { listSpec } from "../../../new_fields/Schema"; export class CurrentUserUtils { private static curr_email: string; @@ -31,13 +37,13 @@ export class CurrentUserUtils { doc.title = this.email; doc.data = new List(); doc.excludeFromLibrary = true; - doc.optionalRightCollection = Docs.SchemaDocument([], { title: "Pending documents" }); + doc.optionalRightCollection = Docs.SchemaDocument(["title"], [], { title: "Pending documents" }); // doc.library = Docs.TreeDocument([doc], { title: `Library: ${CurrentUserUtils.email}` }); // (doc.library as Doc).excludeFromLibrary = true; return doc; } - public static loadCurrentUser(): Promise { + public static async loadCurrentUser(): Promise { let userPromise = rp.get(DocServer.prepend(RouteStore.getCurrUser)).then(response => { if (response) { let obj = JSON.parse(response); @@ -47,7 +53,7 @@ export class CurrentUserUtils { throw new Error("There should be a user! Why does Dash think there isn't one?"); } }); - let userDocPromise = rp.get(DocServer.prepend(RouteStore.getUserDocumentId)).then(id => { + let userDocPromise = await rp.get(DocServer.prepend(RouteStore.getUserDocumentId)).then(id => { if (id) { return DocServer.GetRefField(id).then(field => runInAction(() => this.user_document = field instanceof Doc ? field : this.createUserDocument(id))); @@ -55,14 +61,63 @@ export class CurrentUserUtils { throw new Error("There should be a user id! Why does Dash think there isn't one?"); } }); + try { + const getEnvironment = await fetch("/assets/env.json", { redirect: "follow", method: "GET", credentials: "include" }); + NorthstarSettings.Instance.UpdateEnvironment(await getEnvironment.json()); + await Gateway.Instance.ClearCatalog(); + const extraSchemas = Cast(CurrentUserUtils.UserDocument.DBSchemas, listSpec("string"), []); + let extras = await Promise.all(extraSchemas.map(async sc => await Gateway.Instance.GetSchema("", sc))); + let catprom = CurrentUserUtils.SetNorthstarCatalog(await Gateway.Instance.GetCatalog(), extras); + if (catprom) await Promise.all(catprom); + } catch (e) { + + } return Promise.all([userPromise, userDocPromise]); } /* Northstar catalog ... really just for testing so this should eventually go away */ + // --------------- Northstar hooks ------------- / + static _northstarSchemas: Doc[] = []; @observable private static _northstarCatalog?: Catalog; @computed public static get NorthstarDBCatalog() { return this._northstarCatalog; } + + @action static SetNorthstarCatalog(ctlog: Catalog, extras: Catalog[]) { + CurrentUserUtils.NorthstarDBCatalog = ctlog; + if (ctlog && ctlog.schemas) { + extras.map(ex => ctlog.schemas!.push(ex)); + return ctlog.schemas.map(async schema => { + let schemaDocuments: Doc[] = []; + let attributesToBecomeDocs = CurrentUserUtils.GetAllNorthstarColumnAttributes(schema); + await Promise.all(attributesToBecomeDocs.reduce((promises, attr) => { + promises.push(DocServer.GetRefField(attr.displayName! + ".alias").then(action((field: Opt) => { + if (field instanceof Doc) { + 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(Docs.HistogramDocument(histoOp, { width: 200, height: 200, title: attr.displayName! })); + } + }))); + return promises; + }, [] as Promise[])); + return CurrentUserUtils._northstarSchemas.push(Docs.TreeDocument(schemaDocuments, { width: 50, height: 100, title: schema.displayName! })); + }); + } + } public static set NorthstarDBCatalog(ctlog: Catalog | undefined) { this._northstarCatalog = ctlog; } + public static AddNorthstarSchema(schema: Schema, schemaDoc: Doc) { + if (this._northstarCatalog && CurrentUserUtils._northstarSchemas) { + this._northstarCatalog.schemas!.push(schema); + CurrentUserUtils._northstarSchemas.push(schemaDoc); + let schemas = Cast(CurrentUserUtils.UserDocument.DBSchemas, listSpec("string"), []); + schemas.push(schema.displayName!); + CurrentUserUtils.UserDocument.DBSchemas = new List(schemas); + } + } public static GetNorthstarSchema(name: string): Schema | undefined { return !this._northstarCatalog || !this._northstarCatalog.schemas ? undefined : ArrayUtil.FirstOrDefault(this._northstarCatalog.schemas, (s: Schema) => s.displayName === name); -- cgit v1.2.3-70-g09d2 From b29a0d1cef60b55f609fcd94ad38232ae557e681 Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Thu, 16 May 2019 18:32:57 -0400 Subject: Fixed linter errors --- src/client/goldenLayout.d.ts | 3 +++ src/client/northstar/dash-fields/HistogramField.ts | 2 +- src/client/northstar/model/ModelHelpers.ts | 9 +++---- src/client/util/DragManager.ts | 2 +- src/client/util/RichTextSchema.tsx | 16 +++++------ src/client/util/TooltipTextMenu.tsx | 13 ++++----- src/client/views/DocumentDecorations.tsx | 31 +++++++++++----------- src/client/views/PresentationView.tsx | 4 +-- src/client/views/TemplateMenu.tsx | 4 +-- .../views/collections/CollectionDockingView.tsx | 5 ++-- .../views/collections/CollectionSchemaView.tsx | 10 +++---- .../views/collections/CollectionTreeView.tsx | 9 ++++--- .../collections/collectionFreeForm/MarqueeView.tsx | 13 ++++----- .../views/nodes/CollectionFreeFormDocumentView.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 2 +- src/client/views/nodes/FormattedTextBox.tsx | 8 +++--- src/client/views/nodes/ImageBox.tsx | 2 +- src/client/views/nodes/KeyValueBox.tsx | 2 +- src/client/views/nodes/KeyValuePair.tsx | 3 ++- src/client/views/nodes/VideoBox.tsx | 22 +++++++-------- src/new_fields/CursorField.ts | 6 ++--- src/new_fields/Doc.ts | 4 +-- src/new_fields/ObjectField.ts | 2 +- .../authentication/models/current_user_utils.ts | 2 +- 24 files changed, 91 insertions(+), 85 deletions(-) create mode 100644 src/client/goldenLayout.d.ts (limited to 'src/client/northstar') diff --git a/src/client/goldenLayout.d.ts b/src/client/goldenLayout.d.ts new file mode 100644 index 000000000..b50240563 --- /dev/null +++ b/src/client/goldenLayout.d.ts @@ -0,0 +1,3 @@ + +declare const GoldenLayout: any; +export = GoldenLayout; \ No newline at end of file diff --git a/src/client/northstar/dash-fields/HistogramField.ts b/src/client/northstar/dash-fields/HistogramField.ts index aabc77bb2..1ee2189b9 100644 --- a/src/client/northstar/dash-fields/HistogramField.ts +++ b/src/client/northstar/dash-fields/HistogramField.ts @@ -52,7 +52,7 @@ export class HistogramField extends ObjectField { [Copy]() { let y = this.HistoOp; - let z = this.HistoOp["Copy"]; + let z = this.HistoOp.Copy; return new HistogramField(HistogramOperation.Duplicate(this.HistoOp)); } } \ No newline at end of file diff --git a/src/client/northstar/model/ModelHelpers.ts b/src/client/northstar/model/ModelHelpers.ts index 80bb71224..88e6e72b8 100644 --- a/src/client/northstar/model/ModelHelpers.ts +++ b/src/client/northstar/model/ModelHelpers.ts @@ -32,12 +32,9 @@ export class ModelHelpers { public static GetAggregateParametersIndex(histogramResult: HistogramResult, aggParameters?: AggregateParameters): number { return Array.from(histogramResult.aggregateParameters!).findIndex((value, i, set) => { - if (set[i] instanceof CountAggregateParameters && value instanceof CountAggregateParameters) - return true; - if (set[i] instanceof MarginAggregateParameters && value instanceof MarginAggregateParameters) - return true; - if (set[i] instanceof SumAggregateParameters && value instanceof SumAggregateParameters) - return true; + if (set[i] instanceof CountAggregateParameters && value instanceof CountAggregateParameters) return true; + if (set[i] instanceof MarginAggregateParameters && value instanceof MarginAggregateParameters) return true; + if (set[i] instanceof SumAggregateParameters && value instanceof SumAggregateParameters) return true; return false; }); } diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 26da34e67..05eb5c38a 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -41,7 +41,7 @@ export function SetupDrag(_reference: React.RefObject, docFunc: () export async function DragLinksAsDocuments(dragEle: HTMLElement, x: number, y: number, sourceDoc: Doc) { let srcTarg = sourceDoc.proto; let draggedDocs: Doc[] = []; - let draggedFromDocs: Doc[] = [] + let draggedFromDocs: Doc[] = []; if (srcTarg) { let linkToDocs = await DocListCastAsync(srcTarg.linkedToDocs); let linkFromDocs = await DocListCastAsync(srcTarg.linkedFromDocs); diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index c0e6f7899..3e3e98206 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -97,13 +97,13 @@ export const nodes: { [index: string]: NodeSpec } = { title: dom.getAttribute("title"), alt: dom.getAttribute("alt"), width: Math.min(100, Number(dom.getAttribute("width"))), - } + }; } }], // TODO if we don't define toDom, something weird happens: dragging the image will not move it but clone it. Why? toDOM(node) { - const attrs = { style: `width: ${node.attrs.width}` } - return ["img", { ...node.attrs, ...attrs }] + const attrs = { style: `width: ${node.attrs.width}` }; + return ["img", { ...node.attrs, ...attrs }]; } }, @@ -375,7 +375,7 @@ export class ImageResizeView { const currentX = e.pageX; const diffInPx = currentX - startX; self._outer.style.width = `${startWidth + diffInPx}`; - } + }; const onpointerup = () => { document.removeEventListener("pointermove", onpointermove); @@ -384,11 +384,11 @@ export class ImageResizeView { view.state.tr.setNodeMarkup(getPos(), null, { src: node.attrs.src, width: self._outer.style.width }) .setSelection(view.state.selection)); - } + }; - document.addEventListener("pointermove", onpointermove) - document.addEventListener("pointerup", onpointerup) - } + document.addEventListener("pointermove", onpointermove); + document.addEventListener("pointerup", onpointerup); + }; this._outer.appendChild(this._handle); this._outer.appendChild(this._img); diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx index 6eb654319..223921428 100644 --- a/src/client/util/TooltipTextMenu.tsx +++ b/src/client/util/TooltipTextMenu.tsx @@ -175,7 +175,7 @@ export class TooltipTextMenu { this.linkText.style.width = "150px"; this.linkText.style.overflow = "hidden"; this.linkText.style.color = "white"; - this.linkText.onpointerdown = (e: PointerEvent) => { e.stopPropagation(); } + this.linkText.onpointerdown = (e: PointerEvent) => { e.stopPropagation(); }; let linkBtn = document.createElement("div"); linkBtn.textContent = ">>"; linkBtn.style.width = "20px"; @@ -192,8 +192,9 @@ export class TooltipTextMenu { let docid = href.replace(DocServer.prepend("/doc/"), ""); DocServer.GetRefField(docid).then(action((f: Opt) => { if (f instanceof Doc) { - if (DocumentManager.Instance.getDocumentView(f)) + if (DocumentManager.Instance.getDocumentView(f)) { DocumentManager.Instance.getDocumentView(f)!.props.focus(f); + } else CollectionDockingView.Instance.AddRightSplit(f); } })); @@ -201,7 +202,7 @@ export class TooltipTextMenu { e.stopPropagation(); e.preventDefault(); } - } + }; this.linkDrag = document.createElement("img"); this.linkDrag.src = "https://seogurusnyc.com/wp-content/uploads/2016/12/link-1.png"; this.linkDrag.style.width = "20px"; @@ -216,12 +217,12 @@ export class TooltipTextMenu { { handlers: { dragComplete: action(() => { - let m = dragData.droppedDocuments as Doc[]; + let m = dragData.droppedDocuments; this.makeLink(DocServer.prepend("/doc/" + m[0][Id])); }), }, hideSource: false - }) + }); }; this.linkEditor.appendChild(this.linkDrag); this.linkEditor.appendChild(this.linkText); @@ -239,7 +240,7 @@ export class TooltipTextMenu { e.stopPropagation(); e.preventDefault(); } - } + }; this.tooltip.appendChild(this.linkEditor); } diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index b2c65a31f..7083b1003 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -250,22 +250,21 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> selectedDocs[0].props.removeDocument && selectedDocs[0].props.removeDocument(this._iconDoc); } if (!this._removeIcon) { - if (selectedDocs.length === 1) + if (selectedDocs.length === 1) { this.getIconDoc(selectedDocs[0]).then(icon => selectedDocs[0].props.toggleMinimized()); - else - if (Math.abs(e.pageX - this._downX) < Utils.DRAG_THRESHOLD && - Math.abs(e.pageY - this._downY) < Utils.DRAG_THRESHOLD) { - let docViews = SelectionManager.ViewsSortedVertically(); - let topDocView = docViews[0]; - let ind = topDocView.templates.indexOf(Templates.Bullet.Layout); - if (ind !== -1) { - topDocView.templates.splice(ind, 1); - topDocView.props.Document.subBulletDocs = undefined; - } else { - topDocView.addTemplate(Templates.Bullet); - topDocView.props.Document.subBulletDocs = new List(docViews.filter(v => v !== topDocView).map(v => v.props.Document.proto!)); - } + } else if (Math.abs(e.pageX - this._downX) < Utils.DRAG_THRESHOLD && + Math.abs(e.pageY - this._downY) < Utils.DRAG_THRESHOLD) { + let docViews = SelectionManager.ViewsSortedVertically(); + let topDocView = docViews[0]; + let ind = topDocView.templates.indexOf(Templates.Bullet.Layout); + if (ind !== -1) { + topDocView.templates.splice(ind, 1); + topDocView.props.Document.subBulletDocs = undefined; + } else { + topDocView.addTemplate(Templates.Bullet); + topDocView.props.Document.subBulletDocs = new List(docViews.filter(v => v !== topDocView).map(v => v.props.Document.proto!)); } + } } this._removeIcon = false; } @@ -537,9 +536,9 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> if (temp !== Templates.Bullet.Layout || i === 0) { res.push(temp); } - }) + }); } - return res + return res; }, [] as string[]); let checked = false; docTemps.forEach(temp => { diff --git a/src/client/views/PresentationView.tsx b/src/client/views/PresentationView.tsx index 098e725c7..7d0dc2913 100644 --- a/src/client/views/PresentationView.tsx +++ b/src/client/views/PresentationView.tsx @@ -1,7 +1,7 @@ import { observer } from "mobx-react"; -import React = require("react") +import React = require("react"); import { observable, action, runInAction, reaction } from "mobx"; -import "./PresentationView.scss" +import "./PresentationView.scss"; import "./Main.tsx"; import { DocumentManager } from "../util/DocumentManager"; import { Utils } from "../../Utils"; diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx index cfe1b0663..e5b679e24 100644 --- a/src/client/views/TemplateMenu.tsx +++ b/src/client/views/TemplateMenu.tsx @@ -43,7 +43,7 @@ export class TemplateMenu extends React.Component { @action toggleTemplate = (event: React.ChangeEvent, template: Template): void => { if (event.target.checked) { - if (template.Name == "Bullet") { + if (template.Name === "Bullet") { let topDocView = this.props.docs[0]; topDocView.addTemplate(template); topDocView.props.Document.subBulletDocs = new List(this.props.docs.filter(v => v !== topDocView).map(v => v.props.Document.proto!)); @@ -52,7 +52,7 @@ export class TemplateMenu extends React.Component { } this.props.templates.set(template, true); } else { - if (template.Name == "Bullet") { + if (template.Name === "Bullet") { let topDocView = this.props.docs[0]; topDocView.removeTemplate(template); topDocView.props.Document.subBulletDocs = undefined; diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 58f1e33a1..deec64225 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -83,7 +83,7 @@ export class CollectionDockingView extends React.Component tab.config.component === "DocumentFrameRenderer").some((tab: any, j: number) => { if (Doc.AreProtosEqual(DocumentManager.Instance.getDocumentViewById(tab.config.props.documentId)!.Document, document)) { child.contentItems[j].remove(); @@ -94,8 +94,9 @@ export class CollectionDockingView extends React.Component doc) { let fieldContentView = ; let reference = React.createRef(); let onItemDown = (e: React.PointerEvent) => - (this.props.CollectionView!.props.isSelected() ? + (this.props.CollectionView.props.isSelected() ? SetupDrag(reference, () => props.Document, this.props.moveDocument)(e) : undefined); let applyToDoc = (doc: Doc, run: (args?: { [name: string]: any }) => any) => { const res = run({ this: doc }); @@ -127,7 +127,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { } const run = script.run; //TODO This should be able to be refactored to compile the script once - const val = await DocListCastAsync(this.props.Document[this.props.fieldKey]) + const val = await DocListCastAsync(this.props.Document[this.props.fieldKey]); val && val.forEach(doc => applyToDoc(doc, run)); }}> @@ -230,14 +230,14 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { DocListCast(this.props.Document.data).map(doc => { csv += self.columns.reduce((val, col) => val + (doc[col] ? doc[col]!.toString() : "") + ",", ""); csv = csv.substr(0, csv.length - 1) + "\n"; - }) + }); csv.substring(0, csv.length - 1); let dbName = StrCast(this.props.Document.title); let res = await Gateway.Instance.PostSchema(csv, dbName); if (self.props.CollectionView.props.addDocument) { let schemaDoc = await Docs.DBDocument("https://www.cs.brown.edu/" + dbName, { title: dbName }); if (schemaDoc) { - self.props.CollectionView.props.addDocument(schemaDoc, false); + self.props.CollectionView.props.addDocument(schemaDoc, false); } } } @@ -263,7 +263,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { get previewDocument(): Doc | undefined { const children = DocListCast(this.props.Document[this.props.fieldKey]); const selected = children.length > this._selectedIndex ? FieldValue(children[this._selectedIndex]) : undefined; - return selected ? (this.previewScript && this.previewScript != "this" ? FieldValue(Cast(selected[this.previewScript], Doc)) : selected) : undefined; + return selected ? (this.previewScript && this.previewScript !== "this" ? FieldValue(Cast(selected[this.previewScript], Doc)) : selected) : undefined; } get tableWidth() { return (this.props.PanelWidth() - 2 * this.borderWidth - this.DIVIDER_WIDTH) * (1 - this.splitPercentage / 100); } get previewRegionHeight() { return this.props.PanelHeight() - 2 * this.borderWidth; } diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 70c09d97c..6acef434e 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -56,7 +56,7 @@ class TreeView extends React.Component { } else { CollectionDockingView.Instance.AddRightSplit(this.props.document); } - }; + } get children() { return Cast(this.props.document.data, listSpec(Doc), []); // bcz: needed? .filter(doc => FieldValue(doc)); @@ -184,8 +184,9 @@ class TreeView extends React.Component { {TreeView.GetChildElements(doc instanceof Doc ? [doc] : docList, key !== "data", (doc: Doc) => this.remove(doc, key), this.move, this.props.dropAction)}
); - } else + } else { bulletType = BulletType.Collapsed; + } } }); return
{
; } public static GetChildElements(docs: Doc[], allowMinimized: boolean, remove: ((doc: Doc) => void), move: DragManager.MoveFunction, dropAction: dropActionType) { - return docs.filter(child => child instanceof Doc && !child.excludeFromLibrary && (allowMinimized || !child.isMinimized)).filter(doc => FieldValue(doc)).map(child => - ); + return docs.filter(child => !child.excludeFromLibrary && (allowMinimized || !child.isMinimized)).map(child => + ); } } diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 12edb2c2a..c3c4115b8 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -63,7 +63,7 @@ export class MarqueeView extends React.Component e.preventDefault(); (async () => { let text: string = await navigator.clipboard.readText(); - let ns = text.split("\n").filter(t => t.trim() != "\r" && t.trim() != ""); + let ns = text.split("\n").filter(t => t.trim() !== "\r" && t.trim() !== ""); for (let i = 0; i < ns.length - 1; i++) { while (!(ns[i].trim() === "" || ns[i].endsWith("-\r") || ns[i].endsWith("-") || ns[i].endsWith(";\r") || ns[i].endsWith(";") || @@ -80,7 +80,7 @@ export class MarqueeView extends React.Component let newBox = Docs.TextDocument({ width: 200, height: 35, x: x + indent / 3 * 10, y: y, documentText: "@@@" + line, title: line }); this.props.addDocument(newBox, false); y += 40 * this.props.getTransform().Scale; - }) + }); })(); } else if (e.key === "b" && e.ctrlKey) { //heuristically converts pasted text into a table. @@ -93,9 +93,10 @@ export class MarqueeView extends React.Component e.preventDefault(); (async () => { let text: string = await navigator.clipboard.readText(); - let ns = text.split("\n").filter(t => t.trim() != "\r" && t.trim() != ""); - while (ns.length > 0 && ns[0].split("\t").length < 2) + let ns = text.split("\n").filter(t => t.trim() !== "\r" && t.trim() !== ""); + while (ns.length > 0 && ns[0].split("\t").length < 2) { ns.splice(0, 1); + } if (ns.length > 0) { let columns = ns[0].split("\t"); let docList: Doc[] = []; @@ -109,7 +110,7 @@ export class MarqueeView extends React.Component let doc = new Doc(); columns.forEach((col, i) => doc[columns[i]] = (values.length > i ? ((values[i].indexOf(Number(values[i]).toString()) !== -1) ? Number(values[i]) : values[i]) : undefined)); if (groupAttr) { - doc["_group"] = groupAttr; + doc._group = groupAttr; } doc.title = i.toString(); docList.push(doc); @@ -284,7 +285,7 @@ export class MarqueeView extends React.Component // summarizedDoc.isIconAnimating = new List([scrpt[0], scrpt[1], maxx, maxy, maxw, maxh, Date.now(), 0]); // }); this.props.addLiveTextDocument(summary); - }) + }); } else { this.props.addDocument(newCollection, false); diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 7c7ca9e25..d4f660b3f 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -149,7 +149,7 @@ export class CollectionFreeFormDocumentView extends DocComponent([scrpt[0], scrpt[1], Date.now(), isMinimized ? 1 : 0]) + maximizedDoc.isIconAnimating = new List([scrpt[0], scrpt[1], Date.now(), isMinimized ? 1 : 0]); } } }); diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index cf8bcbb42..428dd9b36 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -244,7 +244,7 @@ export class DocumentView extends DocComponent(Docu const protoDest = destDoc.proto; const protoSrc = sourceDoc.proto; - if (de.mods == "Control") { + if (de.mods === "Control") { let src = protoSrc ? protoSrc : sourceDoc; let dst = protoDest ? protoDest : destDoc; dst.data = src; diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index f24d4ae88..f30022508 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -184,7 +184,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe state: field && field.Data ? EditorState.fromJSON(config, JSON.parse(field.Data)) : EditorState.create(config), dispatchTransaction: this.dispatchTransaction, nodeViews: { - image(node, view, getPos) { return new ImageResizeView(node, view, getPos) } + image(node, view, getPos) { return new ImageResizeView(node, view, getPos); } } }); let text = StrCast(this.props.Document.documentText); @@ -232,9 +232,11 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe let docid = href.replace(DocServer.prepend("/doc/"), "").split("?")[0]; DocServer.GetRefField(docid).then(action((f: Opt) => { if (f instanceof Doc) { - if (DocumentManager.Instance.getDocumentView(f)) + if (DocumentManager.Instance.getDocumentView(f)) { DocumentManager.Instance.getDocumentView(f)!.props.focus(f); - else CollectionDockingView.Instance.AddRightSplit(f); + } else { + CollectionDockingView.Instance.AddRightSplit(f); + } } })); } diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 6472ae711..3cc60a6c5 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -165,7 +165,7 @@ export class ImageBox extends DocComponent(ImageD else if (field instanceof List) paths = field.filter(val => val instanceof ImageField).map(p => (p as ImageField).url.href); let nativeWidth = FieldValue(this.Document.nativeWidth, (this.props.PanelWidth as any) as string ? Number((this.props.PanelWidth as any) as string) : 50); let interactive = InkingControl.Instance.selectedTool ? "" : "-interactive"; - let id = this.props.id; // bcz: used to set id = "isExpander" in templates.tsx + let id = (this.props as any).id; // bcz: used to set id = "isExpander" in templates.tsx return (
{ @observable private _keyInput: string = ""; @observable private _valueInput: string = ""; @computed get splitPercentage() { return NumCast(this.props.Document.schemaSplitPercentage, 50); } - get fieldDocToLayout() { return this.props.fieldKey ? FieldValue(Cast(this.props.Document[this.props.fieldKey], Doc)) : this.props.Document } + get fieldDocToLayout() { return this.props.fieldKey ? FieldValue(Cast(this.props.Document[this.props.fieldKey], Doc)) : this.props.Document; } constructor(props: FieldViewProps) { super(props); diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx index 5de660d57..4f7919f50 100644 --- a/src/client/views/nodes/KeyValuePair.tsx +++ b/src/client/views/nodes/KeyValuePair.tsx @@ -46,8 +46,9 @@ export class KeyValuePair extends React.Component {