in src/app/stores/app_store.ts [1720:2081]
public bindDataToAxis(options: {
object: Specification.PlotSegment;
property?: string;
appendToProperty?: string;
dataExpression: DragData.DataExpression;
type?: AxisDataBindingType;
numericalMode?: NumericalMode;
autoDomainMax: boolean;
autoDomainMin: boolean;
domainMin: number;
domainMax: number;
defineCategories: boolean;
}) {
const { object, property, appendToProperty, dataExpression } = options;
this.normalizeDataExpression(dataExpression);
let groupExpression = dataExpression.expression;
let valueType = dataExpression.valueType;
const propertyValue = object.properties[options.property] as any;
const type = dataExpression.type
? options.type
: this.getBindingByDataKind(options.dataExpression.metadata.kind);
const rawColumnExpression = dataExpression.rawColumnExpression;
if (
rawColumnExpression &&
dataExpression.valueType !== DataType.Date &&
(options.dataExpression.metadata.kind === DataKind.Ordinal ||
options.dataExpression.metadata.kind === DataKind.Categorical)
) {
groupExpression = rawColumnExpression;
valueType = DataType.String;
}
const objectProperties = object.properties[
options.property
] as ObjectProperties;
const expression =
appendToProperty === "dataExpressions" && propertyValue
? ((propertyValue as any).expression as string)
: groupExpression;
const column = getColumnNameByExpression(expression);
const orderByCategories: Array<string> = [];
let dataBinding: Specification.Types.AxisDataBinding = {
type: options.type || type,
// Don't change current expression (use current expression), if user appends data expression ()
expression: expression,
rawExpression:
dataExpression.rawColumnExpression != undefined
? dataExpression.rawColumnExpression
: expression,
valueType: valueType !== undefined ? valueType : null,
gapRatio:
propertyValue?.gapRatio === undefined ? 0.1 : propertyValue.gapRatio,
visible:
objectProperties?.visible !== undefined
? objectProperties?.visible
: true,
side: propertyValue?.side || "default",
style:
(objectProperties?.style as AxisRenderingStyle) ||
deepClone(defaultAxisStyle),
numericalMode:
options.numericalMode != undefined ? options.numericalMode : null,
dataKind:
dataExpression.metadata.kind != undefined
? dataExpression.metadata.kind
: null,
order:
dataExpression.metadata.order !== undefined
? dataExpression.metadata.order
: null,
orderMode:
dataExpression.metadata.orderMode !== undefined
? dataExpression.metadata.orderMode
: null,
autoDomainMax:
options.autoDomainMax != undefined ? options.autoDomainMax : true,
autoDomainMin:
options.autoDomainMin != undefined ? options.autoDomainMin : true,
tickFormat:
<string>objectProperties?.tickFormat !== undefined
? <string>objectProperties?.tickFormat
: null,
tickDataExpression:
<string>objectProperties?.tickDataExpression !== undefined
? <string>objectProperties?.tickDataExpression
: null,
tickFormatType:
(objectProperties?.tickFormatType as TickFormatType) ??
TickFormatType.None,
domainMin:
<number>objectProperties?.domainMin !== undefined
? <number>objectProperties?.domainMin
: null,
domainMax:
<number>objectProperties?.domainMax !== undefined
? <number>objectProperties?.domainMax
: null,
dataDomainMin:
<number>objectProperties?.domainMin !== undefined
? <number>objectProperties?.domainMin
: null,
dataDomainMax:
<number>objectProperties?.domainMax !== undefined
? <number>objectProperties?.domainMax
: null,
enablePrePostGap:
<boolean>objectProperties?.enablePrePostGap !== undefined
? <boolean>objectProperties?.enablePrePostGap
: null,
categories:
<string[]>objectProperties?.categories !== undefined
? <string[]>objectProperties?.categories
: null,
allCategories:
<string[]>objectProperties?.allCategories !== undefined
? <string[]>objectProperties?.allCategories
: <string[]>objectProperties?.categories !== undefined
? <string[]>objectProperties?.categories
: null,
scrollPosition:
<number>objectProperties?.scrollPosition !== undefined
? <number>objectProperties?.scrollPosition
: 0,
allowScrolling:
<boolean>objectProperties?.allowScrolling !== undefined
? <boolean>objectProperties?.allowScrolling
: false,
windowSize:
<number>objectProperties?.windowSize !== undefined
? <number>objectProperties?.windowSize
: 10,
barOffset:
<number>objectProperties?.barOffset !== undefined
? <number>objectProperties?.barOffset
: 0,
offset:
<number>objectProperties?.offset !== undefined
? <number>objectProperties?.offset
: 0,
onTop:
<boolean>objectProperties?.onTop !== undefined
? <boolean>objectProperties?.onTop
: false,
enableSelection:
<boolean>objectProperties?.enableSelection !== undefined
? <boolean>objectProperties?.enableSelection
: false,
orderByCategories:
<string[]>objectProperties?.orderByCategories !== undefined
? <string[]>objectProperties?.orderByCategories
: orderByCategories,
orderByExpression: <string>objectProperties?.orderByExpression ?? column,
};
let expressions = [groupExpression];
if (appendToProperty) {
if (object.properties[appendToProperty] == null) {
object.properties[appendToProperty] = [
{ name: uniqueID(), expression: groupExpression },
];
} else {
(object.properties[appendToProperty] as any[]).push({
name: uniqueID(),
expression: groupExpression,
});
}
expressions = (object.properties[appendToProperty] as any[]).map(
(x) => x.expression
);
if (object.properties[property] == null) {
object.properties[property] = dataBinding;
} else {
dataBinding = object.properties[
property
] as Specification.Types.AxisDataBinding;
}
} else {
object.properties[property] = dataBinding;
}
const groupBy: Specification.Types.GroupBy = this.getGroupingExpression(
object
);
let values: ValueType[] = [];
if (
appendToProperty == "dataExpressions" &&
dataBinding.domainMax !== undefined &&
dataBinding.domainMin !== undefined
) {
// save current range of scale if user adds data
values = values.concat(dataBinding.domainMax, dataBinding.domainMin);
}
for (const expr of expressions) {
if (expr) {
const r = this.chartManager.getGroupedExpressionVector(
dataExpression.table.name,
groupBy,
expr
);
values = values.concat(r);
}
}
if (dataExpression.metadata) {
switch (dataExpression.metadata.kind) {
case Specification.DataKind.Categorical:
case Specification.DataKind.Ordinal:
{
dataBinding.type = AxisDataBindingType.Categorical;
dataBinding.valueType = dataExpression.valueType;
const { categories, order } = this.getCategoriesForDataBinding(
dataExpression.metadata,
dataExpression.valueType,
values
);
dataBinding.orderByCategories = deepClone(categories);
dataBinding.order = order != undefined ? order : null;
dataBinding.allCategories = deepClone(categories);
if (
dataBinding.windowSize == null ||
dataBinding.windowSize > dataBinding.allCategories.length
) {
dataBinding.windowSize =
dataBinding.allCategories?.length ??
Math.ceil(categories.length / 10);
}
dataBinding.categories = categories;
if (dataBinding.allowScrolling) {
const start = Math.floor(
((categories.length - dataBinding.windowSize) / 100) *
dataBinding.scrollPosition
);
dataBinding.categories = categories.slice(
start,
start + dataBinding.windowSize
);
}
}
break;
case Specification.DataKind.Numerical:
{
if (options.numericalMode === NumericalMode.Logarithmic) {
const scale = new Scale.LogarithmicScale();
scale.inferParameters(values as number[]);
if (dataBinding.autoDomainMin) {
dataBinding.domainMin = scale.domainMin;
} else {
dataBinding.domainMin = options.domainMin;
}
if (dataBinding.autoDomainMax) {
dataBinding.domainMax = scale.domainMax;
} else {
dataBinding.domainMax = options.domainMax;
}
dataBinding.type = AxisDataBindingType.Numerical;
dataBinding.numericalMode = NumericalMode.Logarithmic;
} else {
const scale = new Scale.LinearScale();
scale.inferParameters(values as number[]);
if (dataBinding.autoDomainMin) {
dataBinding.domainMin = scale.domainMin;
} else {
dataBinding.domainMin = options.domainMin;
}
if (dataBinding.autoDomainMax) {
dataBinding.domainMax = scale.domainMax;
} else {
dataBinding.domainMax = options.domainMax;
}
dataBinding.type = AxisDataBindingType.Numerical;
dataBinding.numericalMode = NumericalMode.Linear;
}
if (options.defineCategories) {
dataBinding.categories = defineCategories(values);
}
if (dataBinding.windowSize == null) {
dataBinding.windowSize =
(dataBinding.domainMax - dataBinding.domainMin) / 10;
}
dataBinding.dataDomainMin = dataBinding.domainMin;
dataBinding.dataDomainMax = dataBinding.domainMax;
}
break;
case Specification.DataKind.Temporal:
{
const scale = new Scale.DateScale();
scale.inferParameters(values as number[], false);
if (dataBinding.autoDomainMin) {
dataBinding.domainMin = scale.domainMin;
} else {
dataBinding.domainMin = options.domainMin;
}
if (dataBinding.autoDomainMax) {
dataBinding.domainMax = scale.domainMax;
} else {
dataBinding.domainMax = options.domainMax;
}
dataBinding.type = AxisDataBindingType.Numerical;
dataBinding.numericalMode = NumericalMode.Temporal;
const { categories } = this.getCategoriesForDataBinding(
dataExpression.metadata,
dataExpression.valueType,
values
);
dataBinding.allCategories = deepClone(categories);
dataBinding.categories = categories;
if (dataBinding.allowScrolling) {
const start = Math.floor(
((categories.length - dataBinding.windowSize) / 100) *
dataBinding.scrollPosition
);
dataBinding.categories = categories.slice(
start,
start + dataBinding.windowSize
);
}
}
break;
}
}
// Adjust sublayout option if current option is not available
const props = object.properties as Prototypes.PlotSegments.Region2DProperties;
if (props.sublayout) {
if (
props.sublayout.type == Region2DSublayoutType.DodgeX ||
props.sublayout.type == Region2DSublayoutType.DodgeY ||
props.sublayout.type == Region2DSublayoutType.Grid
) {
if (props.xData && props.xData.type == "numerical") {
props.sublayout.type = Region2DSublayoutType.Overlap;
}
if (props.yData && props.yData.type == "numerical") {
props.sublayout.type = Region2DSublayoutType.Overlap;
}
}
//set default sublayout type for Categorical - Categorical data
if (
props.xData &&
props.xData.type == AxisDataBindingType.Categorical &&
props.yData &&
props.yData.type == AxisDataBindingType.Categorical
) {
if (props.sublayout.type == Region2DSublayoutType.Overlap) {
props.sublayout.type = Region2DSublayoutType.Grid;
}
}
}
}