src/spec-transform-auto-layout.ts
import * as utils from './utils/utils';
import {FormatterRegistry} from './formatter-registry';
import * as d3 from 'd3-scale';
import {
ChartSettings,
GPLSpec,
ScaleGuide,
SpecTransformer,
Unit,
UnitGuide
} from './definitions';
import {Plot} from './charts/tau.plot';
interface EngineMeta {
dimension(scaleId: string): {
dimName: string;
dimType: string;
scaleType: string;
};
scaleMeta(scaleId: string, guide: ScaleGuide): {
dimName: string;
dimType: string;
scaleType: string;
values: any[];
isEmpty: boolean;
};
}
var sum = ((arr: number[]) => arr.reduce((sum, x) => (sum + x), 0));
function extendGuide(guide: UnitGuide, targetUnit: Unit, dimension: string, properties: any[]) {
var guide_dim = guide.hasOwnProperty(dimension) ? guide[dimension] : {};
guide_dim = guide_dim || {};
properties.forEach((prop) => {
Object.assign(targetUnit.guide[dimension][prop], guide_dim[prop]);
});
}
var applyCustomProps = (targetUnit: Unit, customUnit: Unit) => {
var guide = customUnit.guide || {};
var config = {
x: ['label'],
y: ['label'],
size: ['label'],
color: ['label'],
padding: []
};
Object.keys(config).forEach((name) => {
let properties = config[name];
extendGuide(guide, targetUnit, name, properties);
});
Object.assign(targetUnit.guide, Object.keys(guide).reduce((obj, k) => {
if (!config.hasOwnProperty(k)) {
obj[k] = guide[k];
}
return obj;
}, {}));
return targetUnit;
};
var extendLabel = function (guide: UnitGuide, dimension: string, extend?) {
guide[dimension] = utils.defaults(guide[dimension] || {}, {
label: ''
});
guide[dimension].label = utils.isObject(guide[dimension].label) ?
guide[dimension].label :
{text: guide[dimension].label};
guide[dimension].label = utils.defaults(
guide[dimension].label,
extend || {},
{
padding: 32,
rotate: 0,
textAnchor: 'middle',
cssClass: 'label',
dock: null
}
);
return guide[dimension];
};
var extendAxis = function (guide: UnitGuide, dimension: 'x' | 'y', extend?) {
guide[dimension] = utils.defaults(
guide[dimension],
extend || {},
{
padding: 0,
density: 30,
rotate: 0,
tickPeriod: null,
tickFormat: null,
autoScale: true
}
);
guide[dimension].tickFormat = guide[dimension].tickFormat || guide[dimension].tickPeriod;
guide[dimension].nice = guide[dimension].hasOwnProperty('nice') ?
guide[dimension].nice :
guide[dimension].autoScale;
return guide[dimension];
};
var applyNodeDefaults = (node: Unit) => {
node.options = node.options || {};
node.guide = node.guide || {};
node.guide.padding = utils.defaults(node.guide.padding || {}, {l: 0, b: 0, r: 0, t: 0});
node.guide.x = extendLabel(node.guide, 'x', {
textAnchor: 'end'
});
node.guide.x = extendAxis(node.guide, 'x', {
cssClass: 'x axis',
scaleOrient: 'bottom',
textAnchor: 'middle'
});
node.guide.y = extendLabel(node.guide, 'y', {
rotate: -90,
textAnchor: 'end',
});
node.guide.y = extendAxis(node.guide, 'y', {
cssClass: 'y axis',
scaleOrient: 'left',
textAnchor: 'end'
});
node.guide.size = extendLabel(node.guide, 'size');
node.guide.color = extendLabel(node.guide, 'color');
return node;
};
var inheritProps = (childUnit: Unit, root: Unit) => {
childUnit.guide = childUnit.guide || {};
childUnit.guide.padding = childUnit.guide.padding || {l: 0, t: 0, r: 0, b: 0};
// leaf elements should inherit coordinates properties
if (!childUnit.hasOwnProperty('units')) {
childUnit = utils.defaults(childUnit, root);
childUnit.guide = utils.defaults(childUnit.guide, utils.clone(root.guide));
childUnit.guide.x = utils.defaults(childUnit.guide.x, utils.clone(root.guide.x));
childUnit.guide.y = utils.defaults(childUnit.guide.y, utils.clone(root.guide.y));
}
return childUnit;
};
var createSelectorPredicates = (root: Unit) => {
var children = root.units || [];
var isLeaf = !root.hasOwnProperty('units');
var isLeafParent = !children.some((c) => c.hasOwnProperty('units'));
return {
type: root.type,
isLeaf: isLeaf,
isLeafParent: !isLeaf && isLeafParent
};
};
var getMaxTickLabelSize = function (domainValues, formatter, fnCalcTickLabelSize, axisLabelLimit) {
if (domainValues.length === 0) {
return {width: 0, height: 0};
}
if (formatter === null) {
var size = fnCalcTickLabelSize('TauChart Library');
size.width = axisLabelLimit * 0.625; // golden ratio
return size;
}
if (domainValues.every(d => (typeof d === 'number'))) {
domainValues = d3.scaleLinear().domain(domainValues).ticks();
}
var maxXTickText = domainValues.reduce((prev, value) => {
let computed = formatter(value).toString().length;
if (!prev.computed || computed > prev.computed) {
return {
value: value,
computed: computed
};
}
return prev;
}, {}).value;
return fnCalcTickLabelSize(formatter(maxXTickText));
};
var getTickFormat = (dim, defaultFormats) => {
var dimType = dim.dimType;
var scaleType = dim.scaleType;
var specifier = '*';
var key = [dimType, scaleType, specifier].join(':');
var tag = [dimType, scaleType].join(':');
return defaultFormats[key] || defaultFormats[tag] || defaultFormats[dimType] || null;
};
var getSettings = (settings, prop, dimType) => {
return settings.hasOwnProperty(`${prop}:${dimType}`) ?
settings[`${prop}:${dimType}`] :
settings[`${prop}`];
};
var shortFormat = (format, utc) => {
var timeFormats = ['day', 'week', 'month'];
if (timeFormats.indexOf(format) >= 0) {
format += `-short${utc ? '-utc' : ''}`;
}
return format;
};
var rotateBox = ({width, height}, angle) => {
var rad = Math.abs(utils.toRadian(angle));
return {
width: Math.max(Math.cos(rad) * width, height),
height: Math.max(Math.sin(rad) * width, height)
};
};
var getTextAnchorByAngle = (xAngle: number, xOrY = 'x') => {
var angle = utils.normalizeAngle(xAngle);
var xRules: [number, number, string][] = (xOrY === 'x') ?
([
[0, 45, 'middle'],
[45, 135, 'start'],
[135, 225, 'middle'],
[225, 315, 'end'],
[315, 360, 'middle']
]) :
([
[0, 90, 'end'],
[90, 135, 'middle'],
[135, 225, 'start'],
[225, 315, 'middle'],
[315, 360, 'end']
]);
var i = xRules.findIndex((r) => (angle >= r[0] && angle < r[1]));
return xRules[i][2];
};
var wrapLine = (box, lineWidthLimit, linesCountLimit) => {
let guessLinesCount = Math.ceil(box.width / lineWidthLimit);
let koeffLinesCount = Math.min(guessLinesCount, linesCountLimit);
return {
height: koeffLinesCount * box.height,
width: lineWidthLimit
};
};
function calcXYGuide(
guide: UnitGuide,
settings: ChartSettings,
xMeta,
yMeta,
inlineLabels?: boolean,
isFacetUnit?: boolean
) {
var xValues = xMeta.values;
var yValues = yMeta.values;
var xIsEmptyAxis = (xMeta.isEmpty || guide.x.hideTicks);
var yIsEmptyAxis = (yMeta.isEmpty || guide.y.hideTicks);
var maxXTickBox = getMaxTickLabelSize(
xValues,
FormatterRegistry.get(guide.x.tickFormat, guide.x.tickFormatNullAlias),
settings.getAxisTickLabelSize,
settings.xAxisTickLabelLimit);
var maxYTickBox = getMaxTickLabelSize(
yValues,
FormatterRegistry.get(guide.y.tickFormat, guide.y.tickFormatNullAlias),
settings.getAxisTickLabelSize,
settings.yAxisTickLabelLimit);
var multiLinesXBox = maxXTickBox;
var multiLinesYBox = maxYTickBox;
if (maxXTickBox.width > settings.xAxisTickLabelLimit) {
guide.x.tickFormatWordWrap = true;
guide.x.tickFormatWordWrapLines = settings.xTickWordWrapLinesLimit;
multiLinesXBox = wrapLine(maxXTickBox, settings.xAxisTickLabelLimit, settings.xTickWordWrapLinesLimit);
}
if (maxYTickBox.width > settings.yAxisTickLabelLimit) {
guide.y.tickFormatWordWrap = true;
guide.y.tickFormatWordWrapLines = settings.yTickWordWrapLinesLimit;
multiLinesYBox = wrapLine(maxYTickBox, settings.yAxisTickLabelLimit, settings.yTickWordWrapLinesLimit);
}
if (isFacetUnit) {
guide.y.tickFormatWordWrap = false;
guide.y.tickFormatWordWrapLines = 1;
multiLinesYBox = wrapLine(maxYTickBox, settings.yAxisTickLabelLimit * 2, 1);
multiLinesYBox.width = 20;
}
var kxAxisW = xIsEmptyAxis ? 0 : 1;
var kyAxisW = yIsEmptyAxis ? 0 : 1;
var xLabel = guide.x.label;
var yLabel = guide.y.label;
var kxLabelW = (xLabel.text && !xLabel.hide) ? 1 : 0;
var kyLabelW = (yLabel.text && !yLabel.hide) ? 1 : 0;
var rotXBox = rotateBox(multiLinesXBox, guide.x.rotate);
var rotYBox = rotateBox(multiLinesYBox, guide.y.rotate);
var paddingB = (guide.padding && guide.padding.b) ? guide.padding.b : 0;
var paddingL = (guide.padding && guide.padding.l) ? guide.padding.l : 0;
var paddingNoTicksB = (guide.paddingNoTicks && guide.paddingNoTicks.b) ? guide.paddingNoTicks.b : 0;
var paddingNoTicksL = (guide.paddingNoTicks && guide.paddingNoTicks.l) ? guide.paddingNoTicks.l : 0;
if (inlineLabels) {
xLabel.padding = (-settings.xAxisPadding - settings.xFontLabelHeight) / 2 + settings.xFontLabelHeight;
xLabel.paddingNoTicks = xLabel.padding;
yLabel.padding = (-settings.yAxisPadding - settings.yFontLabelHeight) / 2;
yLabel.paddingNoTicks = yLabel.padding;
kxLabelW = 0;
kyLabelW = 0;
} else {
xLabel.padding = sum([
(kxAxisW * (settings.xTickWidth + rotXBox.height)),
(kxLabelW * (settings.distToXAxisLabel + settings.xFontLabelHeight))
]);
xLabel.paddingNoTicks = (kxLabelW * (settings.distToXAxisLabel + settings.xFontLabelHeight));
yLabel.padding = sum([
(kyAxisW * (settings.yTickWidth + rotYBox.width)),
(kyLabelW * settings.distToYAxisLabel)
]);
yLabel.paddingNoTicks = (kyLabelW * settings.distToYAxisLabel);
}
if (isFacetUnit) {
yLabel.padding = 0;
yLabel.paddingNoTicks = 0;
}
const bottomBorder = settings.xFontLabelDescenderLineHeight; // for font descender line
guide.padding = Object.assign(
(guide.padding),
{
b: (guide.x.hide) ?
paddingB :
sum([
(guide.x.padding),
(kxAxisW * (settings.xTickWidth + rotXBox.height)),
(kxLabelW * (settings.distToXAxisLabel + settings.xFontLabelHeight + bottomBorder))
]),
l: (guide.y.hide) ?
paddingL :
sum([
(guide.y.padding),
(isFacetUnit ? 0 : (kyAxisW * (settings.yTickWidth + rotYBox.width))),
(kyLabelW * (settings.distToYAxisLabel + settings.yFontLabelHeight))
])
});
guide.paddingNoTicks = Object.assign(
{},
(guide.paddingNoTicks),
{
b: (guide.x.hide) ?
paddingNoTicksB :
sum([
(guide.x.padding),
(kxLabelW * (settings.distToXAxisLabel + settings.xFontLabelHeight + bottomBorder))
]),
l: (guide.y.hide) ?
paddingNoTicksL :
sum([
(guide.y.padding),
(kyLabelW * (settings.distToYAxisLabel + settings.yFontLabelHeight))
])
});
guide.x = Object.assign(
(guide.x),
{
density: (rotXBox.width + getSettings(settings, 'xDensityPadding', xMeta.dimType) * 2),
tickFontHeight: maxXTickBox.height,
$minimalDomain: xValues.length,
$maxTickTextW: multiLinesXBox.width,
$maxTickTextH: multiLinesXBox.height,
tickFormatWordWrapLimit: settings.xAxisTickLabelLimit
});
guide.y = Object.assign(
(guide.y),
{
density: (rotYBox.height + getSettings(settings, 'yDensityPadding', yMeta.dimType) * 2),
tickFontHeight: maxYTickBox.height,
$minimalDomain: yValues.length,
$maxTickTextW: multiLinesYBox.width,
$maxTickTextH: multiLinesYBox.height,
tickFormatWordWrapLimit: settings.yAxisTickLabelLimit
});
return guide;
}
interface CalcUnitArgs {
unit: Unit;
meta: EngineMeta;
settings: ChartSettings;
allowXVertical: boolean;
allowYVertical: boolean;
inlineLabels: boolean;
}
var calcUnitGuide = function ({unit, meta, settings, allowXVertical, allowYVertical, inlineLabels}: CalcUnitArgs) {
var dimX = meta.dimension(unit.x);
var dimY = meta.dimension(unit.y);
var xMeta = meta.scaleMeta(unit.x, unit.guide.x);
var yMeta = meta.scaleMeta(unit.y, unit.guide.y);
var xIsEmptyAxis = (xMeta.isEmpty);
var yIsEmptyAxis = (yMeta.isEmpty);
unit.guide.x.tickFormat = shortFormat(
(unit.guide.x.tickFormat || getTickFormat(dimX, settings.defaultFormats)),
settings.utcTime);
unit.guide.y.tickFormat = shortFormat(
(unit.guide.y.tickFormat || getTickFormat(dimY, settings.defaultFormats)),
settings.utcTime);
var isXVertical = allowXVertical ? !(dimX.dimType === 'measure') : false;
var isYVertical = allowYVertical ? !(dimY.dimType === 'measure') : false;
unit.guide.x.padding = xIsEmptyAxis ? 0 : settings.xAxisPadding;
unit.guide.x.paddingNoTicks = unit.guide.x.padding;
unit.guide.y.padding = yIsEmptyAxis ? 0 : settings.yAxisPadding;
unit.guide.y.paddingNoTicks = unit.guide.y.padding;
unit.guide.x.rotate = isXVertical ? -90 : 0;
unit.guide.x.textAnchor = getTextAnchorByAngle(unit.guide.x.rotate, 'x');
unit.guide.y.rotate = isYVertical ? -90 : 0;
unit.guide.y.textAnchor = getTextAnchorByAngle(unit.guide.y.rotate, 'y');
unit.guide = calcXYGuide(unit.guide, settings, xMeta, yMeta, inlineLabels, utils.isFacetUnit(unit));
if (inlineLabels) {
let xLabel = unit.guide.x.label;
let yLabel = unit.guide.y.label;
xLabel.cssClass += ' inline';
xLabel.dock = 'right';
xLabel.textAnchor = 'end';
yLabel.cssClass += ' inline';
yLabel.dock = 'right';
yLabel.textAnchor = 'end';
}
return unit;
};
type SpecEngineFunction = (srcSpec: {unit: Unit}, meta: EngineMeta, settings: ChartSettings) => {unit: Unit};
interface SpecEngines {
[engine: string]: SpecEngineFunction;
}
var SpecEngineTypeMap: SpecEngines = {
NONE: (srcSpec, meta, settings) => {
var spec = utils.clone(srcSpec);
fnTraverseSpec(
utils.clone(spec.unit),
spec.unit,
(selectorPredicates, unit) => {
unit.guide.x.tickFontHeight = settings.getAxisTickLabelSize('X').height;
unit.guide.y.tickFontHeight = settings.getAxisTickLabelSize('Y').height;
unit.guide.x.tickFormatWordWrapLimit = settings.xAxisTickLabelLimit;
unit.guide.y.tickFormatWordWrapLimit = settings.yAxisTickLabelLimit;
return unit;
});
return spec;
},
'BUILD-LABELS': (srcSpec, meta) => {
var spec = utils.clone(srcSpec);
var xLabels = [];
var yLabels = [];
var xUnit = null;
var yUnit = null;
utils.traverseJSON(
spec.unit,
'units',
createSelectorPredicates,
(selectors, unit: Unit) => {
if (selectors.isLeaf) {
return unit;
}
if (!xUnit && unit.x) {
xUnit = unit;
}
if (!yUnit && unit.y) {
yUnit = unit;
}
unit.guide = unit.guide || {};
unit.guide.x = unit.guide.x || {label: {text: ''}};
unit.guide.y = unit.guide.y || {label: {text: ''}};
unit.guide.x.label = utils.isObject(unit.guide.x.label)
? unit.guide.x.label
: {text: unit.guide.x.label && unit.guide.x.label.text ? unit.guide.x.label.text : ''};
unit.guide.y.label = utils.isObject(unit.guide.y.label)
? unit.guide.y.label
: {text: unit.guide.y.label && unit.guide.y.label.text ? unit.guide.y.label.text : ''};
if (unit.x) {
unit.guide.x.label.text = unit.guide.x.label.text || meta.dimension(unit.x).dimName;
}
if (unit.y) {
unit.guide.y.label.text = unit.guide.y.label.text || meta.dimension(unit.y).dimName;
}
var x = unit.guide.x.label.text;
if (x) {
xLabels.push(x);
unit.guide.x.tickFormatNullAlias = unit.guide.x.hasOwnProperty('tickFormatNullAlias') ?
unit.guide.x.tickFormatNullAlias :
'No ' + x;
unit.guide.x.label.text = '';
unit.guide.x.label._original_text = x;
}
var y = unit.guide.y.label.text;
if (y) {
yLabels.push(y);
unit.guide.y.tickFormatNullAlias = unit.guide.y.hasOwnProperty('tickFormatNullAlias') ?
unit.guide.y.tickFormatNullAlias :
'No ' + y;
unit.guide.y.label.text = '';
unit.guide.y.label._original_text = y;
}
return unit;
});
const rightArrow = ' \u2192 ';
if (xUnit) {
xUnit.guide.x.label.text = (xUnit.guide.x.label.hide) ? '' : xLabels.join(rightArrow);
}
if (yUnit) {
yUnit.guide.y.label.text = (yUnit.guide.y.label.hide) ? '' : yLabels.join(rightArrow);
}
return spec;
},
'BUILD-GUIDE': (srcSpec, meta, settings) => {
var spec = utils.clone(srcSpec);
fnTraverseSpec(
utils.clone(spec.unit),
spec.unit,
(selectorPredicates, unit: Unit) => {
if (selectorPredicates.isLeaf) {
return unit;
}
var isFacetUnit = (!selectorPredicates.isLeaf && !selectorPredicates.isLeafParent);
var xMeta = meta.scaleMeta(unit.x, unit.guide.x);
var yMeta = meta.scaleMeta(unit.y, unit.guide.y);
var isXVertical = !isFacetUnit && (Boolean(xMeta.dimType) && xMeta.dimType !== 'measure');
unit.guide.x.rotate = unit.guide.x.rotate || (isXVertical ? -90 : 0);
unit.guide.x.textAnchor = getTextAnchorByAngle(unit.guide.x.rotate);
unit.guide.x.tickFormat = unit.guide.x.tickFormat || getTickFormat(xMeta, settings.defaultFormats);
unit.guide.y.tickFormat = unit.guide.y.tickFormat || getTickFormat(yMeta, settings.defaultFormats);
unit.guide.x.padding = (isFacetUnit ? 0 : settings.xAxisPadding);
unit.guide.x.paddingNoTicks = unit.guide.x.padding;
unit.guide.y.padding = (isFacetUnit ? 0 : settings.yAxisPadding);
unit.guide.y.paddingNoTicks = unit.guide.y.padding;
unit.guide = calcXYGuide(
unit.guide,
utils.defaults(
{
distToXAxisLabel: (xMeta.isEmpty) ? settings.xTickWidth : settings.distToXAxisLabel,
distToYAxisLabel: (yMeta.isEmpty) ? settings.yTickWidth : settings.distToYAxisLabel
},
settings),
xMeta,
yMeta,
null,
utils.isFacetUnit(unit));
unit.guide.x = Object.assign(
(unit.guide.x),
{
cssClass: (isFacetUnit) ? (unit.guide.x.cssClass + ' facet-axis') : (unit.guide.x.cssClass),
avoidCollisions: (isFacetUnit) ? true : (unit.guide.x.avoidCollisions)
});
unit.guide.y = Object.assign(
(unit.guide.y),
{
cssClass: (isFacetUnit) ? (unit.guide.y.cssClass + ' facet-axis') : (unit.guide.y.cssClass),
avoidCollisions: (isFacetUnit) ? false : (unit.guide.y.avoidCollisions)
});
unit.guide = Object.assign(
(unit.guide),
{
showGridLines: ((unit.guide.hasOwnProperty('showGridLines')) ?
(unit.guide.showGridLines) :
(selectorPredicates.isLeafParent ? 'xy' : ''))
});
return unit;
});
return spec;
},
'BUILD-COMPACT': (srcSpec, meta, settings) => {
var spec = utils.clone(srcSpec);
fnTraverseSpec(
utils.clone(spec.unit),
spec.unit,
(selectorPredicates, unit: Unit) => {
if (selectorPredicates.isLeaf) {
return unit;
}
if (!unit.guide.hasOwnProperty('showGridLines')) {
unit.guide.showGridLines = selectorPredicates.isLeafParent ? 'xy' : '';
}
if (selectorPredicates.isLeafParent) {
return calcUnitGuide({
unit,
meta,
settings: utils.defaults(
{
xTickWordWrapLinesLimit: 1,
yTickWordWrapLinesLimit: 1
},
settings),
allowXVertical: true,
allowYVertical: false,
inlineLabels: true
});
}
// facet level
unit.guide.x.cssClass += ' facet-axis compact';
unit.guide.x.avoidCollisions = true;
unit.guide.y.cssClass += ' facet-axis compact';
unit.guide.y.avoidCollisions = true;
return calcUnitGuide({
unit,
meta,
settings: utils.defaults(
{
xAxisPadding: 0,
yAxisPadding: 0,
distToXAxisLabel: 0,
distToYAxisLabel: 0,
xTickWordWrapLinesLimit: 1,
yTickWordWrapLinesLimit: 1
},
settings),
allowXVertical: false,
allowYVertical: true,
inlineLabels: false
});
});
return spec;
}
};
SpecEngineTypeMap.AUTO = (srcSpec, meta, settings) => {
return ['BUILD-LABELS', 'BUILD-GUIDE'].reduce(
(spec, engineName) => SpecEngineTypeMap[engineName](spec, meta, settings),
srcSpec
);
};
SpecEngineTypeMap.COMPACT = (srcSpec, meta, settings) => {
return ['BUILD-LABELS', 'BUILD-COMPACT'].reduce(
(spec, engineName) => SpecEngineTypeMap[engineName](spec, meta, settings),
srcSpec
);
};
var fnTraverseSpec = (orig, specUnitRef, transformRules) => {
var xRef = applyNodeDefaults(specUnitRef);
xRef = transformRules(createSelectorPredicates(xRef), xRef);
xRef = applyCustomProps(xRef, orig);
var prop = utils.omit(xRef, 'units');
(xRef.units || []).forEach((unit) => fnTraverseSpec(utils.clone(unit), inheritProps(unit, prop), transformRules));
return xRef;
};
var SpecEngineFactory = {
get: (typeName, settings, srcSpec, fnCreateScale) => {
var engine = (SpecEngineTypeMap[typeName] || SpecEngineTypeMap.NONE);
var meta: EngineMeta = {
dimension: (scaleId) => {
var scaleCfg = srcSpec.scales[scaleId];
var dim = srcSpec.sources[scaleCfg.source].dims[scaleCfg.dim] || {};
return {
dimName: scaleCfg.dim,
dimType: dim.type,
scaleType: scaleCfg.type
};
},
scaleMeta: (scaleId) => {
var scale = fnCreateScale('pos', scaleId);
var values = scale.domain();
var scaleCfg = srcSpec.scales[scaleId];
var dim = srcSpec.sources[scaleCfg.source].dims[scaleCfg.dim] || {};
return {
dimName: scaleCfg.dim,
dimType: dim.type,
scaleType: scaleCfg.type,
values: values,
isEmpty: (dim.type == null)
// isEmpty: (source == '?')
// isEmpty: ((values.filter((x) => !(x === undefined)).length) === 0)
};
}
};
var unitSpec = {unit: utils.clone(srcSpec.unit)};
var fullSpec = engine(unitSpec, meta, settings);
srcSpec.unit = fullSpec.unit;
return srcSpec;
}
};
export class SpecTransformAutoLayout implements SpecTransformer {
spec: GPLSpec;
isApplicable: boolean;
constructor(spec: GPLSpec) {
this.spec = spec;
this.isApplicable = utils.isSpecRectCoordsOnly(spec.unit);
}
transform(chart: Plot) {
var spec = this.spec;
if (!this.isApplicable) {
return spec;
}
var size = spec.settings.size;
var rule = spec.settings.specEngine.find((rule) => (
(size.width <= rule.width) ||
(size.height <= rule.height)
));
return SpecEngineFactory.get(
rule.name,
spec.settings,
spec,
(type, alias) => chart.getScaleInfo(alias || `${type}:default`)
);
}
}