Skip to content

Commit

Permalink
feat: support expression for text align/baseline
Browse files Browse the repository at this point in the history
  • Loading branch information
kanitw committed Sep 13, 2020
1 parent 70f9b78 commit bcbd241
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 11 deletions.
23 changes: 17 additions & 6 deletions src/compile/mark/encode/position-align.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import {Align, SignalRef} from 'vega';
import {Align, SignalRef, TextBaseline} from 'vega';
import {getVgPositionChannel} from '../../../channel';
import {Config} from '../../../config';
import {MarkDef} from '../../../mark';
import {VgEncodeChannel} from '../../../vega.schema';
import * as log from '../../../log';
import {Mark, MarkDef} from '../../../mark';
import {isSignalRef, VgEncodeChannel} from '../../../vega.schema';
import {getMarkPropOrConfig} from '../../common';

const ALIGNED_X_CHANNEL: Record<Align, VgEncodeChannel> = {
Expand All @@ -19,7 +20,7 @@ const BASELINED_Y_CHANNEL = {

export function vgAlignedPositionChannel(
channel: 'x' | 'y' | 'radius' | 'theta',
markDef: MarkDef,
markDef: MarkDef<Mark, SignalRef>,
config: Config<SignalRef>,
defaultAlign: 'top' | 'middle' = 'middle'
) {
Expand All @@ -28,9 +29,19 @@ export function vgAlignedPositionChannel(
}
const alignChannel = channel === 'x' ? 'align' : 'baseline';
const align = getMarkPropOrConfig(alignChannel, markDef, config);

let alignExcludingSignal: Align | TextBaseline;

if (isSignalRef(align)) {
log.warn(log.message.rangeMarkAlignmentCannotBeExpression(alignChannel));
alignExcludingSignal = undefined;
} else {
alignExcludingSignal = align;
}

if (channel === 'x') {
return ALIGNED_X_CHANNEL[align || (defaultAlign === 'top' ? 'left' : 'center')];
return ALIGNED_X_CHANNEL[alignExcludingSignal || (defaultAlign === 'top' ? 'left' : 'center')];
} else {
return BASELINED_Y_CHANNEL[align || defaultAlign];
return BASELINED_Y_CHANNEL[alignExcludingSignal || defaultAlign];
}
}
9 changes: 7 additions & 2 deletions src/log/message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ import {AggregateOp} from 'vega';
import {Aggregate} from '../aggregate';
import {
Channel,
ExtendedChannel,
FacetChannel,
GeoPositionChannel,
getSizeChannel,
PositionScaleChannel,
ScaleChannel,
ExtendedChannel
ScaleChannel
} from '../channel';
import {HiddenCompositeAggregate, TypedFieldDef, Value} from '../channeldef';
import {SplitParentProperty} from '../compile/split';
Expand Down Expand Up @@ -210,6 +210,11 @@ export function discreteChannelCannotEncode(channel: Channel, type: Type) {
}

// MARK

export function rangeMarkAlignmentCannotBeExpression(align: 'align' | 'baseline') {
return `The ${align} for range marks cannot be an expression`;
}

export function lineWithRange(hasX2: boolean, hasY2: boolean) {
const channels = hasX2 && hasY2 ? 'x2 and y2' : hasX2 ? 'x2' : 'y2';
return `Line mark is for continuous lines and thus cannot be used with ${channels}. We will use the rule mark (line segments) instead.`;
Expand Down
15 changes: 12 additions & 3 deletions src/mark.ts
Original file line number Diff line number Diff line change
Expand Up @@ -228,13 +228,22 @@ export interface MarkConfig<ES extends ExprRef | SignalRef>

/**
* The horizontal alignment of the text or ranged marks (area, bar, image, rect, rule). One of `"left"`, `"right"`, `"center"`.
*
* __Note:__ Expression reference is *not* supported for range marks.
*/
align?: Align; // Vega doesn't apply align to ranged marks. Since some logic depends on this property, Vega-Lite does NOT allow signal for align.
align?: Align | ES;

/**
* The vertical text baseline. One of `"alphabetic"` (default), `"top"`, `"middle"`, `"bottom"`, `"line-top"`, or `"line-bottom"`. The `"line-top"` and `"line-bottom"` values operate similarly to `"top"` and `"bottom"`, but are calculated relative to the `lineHeight` rather than `fontSize` alone.
* For text marks, the vertical text baseline. One of `"alphabetic"` (default), `"top"`, `"middle"`, `"bottom"`, `"line-top"`, `"line-bottom", or an expression reference that provides one of the valid values.
* The `"line-top"` and `"line-bottom"` values operate similarly to `"top"` and `"bottom"`,
* but are calculated relative to the `lineHeight` rather than `fontSize` alone.
*
* For range marks, the vertical alignment of the marks. One of `"top"`, `"middle"`, `"bottom"`.
*
* __Note:__ Expression reference is *not* supported for range marks.
*
*/
baseline?: TextBaseline; // Vega doesn't apply align to ranged marks. Since some logic depends on this property, Vega-Lite does NOT allow signal for baseline.
baseline?: TextBaseline | ES;

/**
* - For arc marks, the arc length in radians if theta2 is not specified, otherwise the start arc angle. (A value of 0 indicates up or “north”, increasing values proceed clockwise.)
Expand Down
17 changes: 17 additions & 0 deletions test/compile/mark/rect.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,23 @@ describe('Mark: Rect', () => {
});
});

it(
'should throw warning if align is expression',
log.wrap(localLogger => {
const model = parseUnitModelWithScaleAndLayoutSize({
data: {url: 'data/cars.json'},
mark: {type: 'rect', width: 50, height: 49, align: {expr: 'test'}, baseline: 'top'},
encoding: {
x: {field: 'x', type: 'quantitative'},
y: {type: 'quantitative', field: 'y'}
}
});
rect.encodeEntry(model);

expect(localLogger.warns[0]).toEqual(log.message.rangeMarkAlignmentCannotBeExpression('align'));
})
);

describe('simple with width and height with right align and bottom baseline', () => {
const model = parseUnitModelWithScaleAndLayoutSize({
data: {url: 'data/cars.json'},
Expand Down

0 comments on commit bcbd241

Please sign in to comment.