Socket
Socket
Sign inDemoInstall

vega-lite

Package Overview
Dependencies
Maintainers
2
Versions
470
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

vega-lite - npm Package Compare versions

Comparing version 1.0.12 to 1.0.13

examples/specs/box_plot.json

1

CONTRIBUTING.md

@@ -101,2 +101,3 @@ # Contributing

`vl.compile` is in `src/compile/compile.ts`.
- All interface for Vega-Lite syntax should be declared at the top-level of the `src/` folder.

@@ -103,0 +104,0 @@ - `test/` - Code for unit testing. `test`'s structure reflects `src`'s' directory structure.

2

examples/all-examples.json

@@ -1,1 +0,1 @@

["area","area_vertical","bar","bar_1d","bar_aggregate","bar_aggregate_size","bar_aggregate_vertical","bar_filter_calc","bar_grouped","bar_grouped_horizontal","bar_layered_transparent","bar_yearmonth","bubble_health_income","circle","github_punchcard","histogram","layer_bar_line","layer_bar_line_union","layer_histogram","layer_line_color_rule","line","line_color","line_detail","line_monotone","line_month","line_slope","line_step","minimal","point_1d","point_color","point_dot_timeunit_color","point_filled","point_ordinal_color","scatter","scatter_aggregate_detail","scatter_binned","scatter_binned_color","scatter_binned_size","scatter_bubble","scatter_color","scatter_color_custom","scatter_color_order","scatter_color_ordinal","scatter_color_ordinal_custom","scatter_color_quantitative","scatter_color_shape_constant","scatter_colored_with_shape","scatter_connected","scatter_log","scatter_opacity","square","stacked_area","stacked_area_normalize","stacked_area_ordinal","stacked_area_stream","stacked_bar_1d","stacked_bar_h","stacked_bar_h_order","stacked_bar_normalize","stacked_bar_population","stacked_bar_size","stacked_bar_sum_opacity","stacked_bar_v","stacked_bar_weather","text_scatter_colored","text_table_heatmap","tick_dot","tick_dot_thickness","tick_strip","trellis_anscombe","trellis_bar","trellis_bar_histogram","trellis_barley","trellis_row_column","trellis_scatter","trellis_scatter_binned_row","trellis_stacked_bar"]
["area","area_vertical","bar","bar_1d","bar_aggregate","bar_aggregate_size","bar_aggregate_vertical","bar_filter_calc","bar_grouped","bar_grouped_horizontal","bar_layered_transparent","bar_yearmonth","box_plot","bubble_health_income","circle","errorbar_aggregate","errorbar_horizontal_aggregate","github_punchcard","histogram","layer_bar_line","layer_bar_line_union","layer_histogram","layer_line_color_rule","line","line_color","line_detail","line_monotone","line_month","line_quarter","line_quarter_legend","line_slope","line_step","minimal","overlay_area_full","overlay_area_short","overlay_line_full","overlay_line_short","point_1d","point_color","point_dot_timeunit_color","point_filled","point_ordinal_color","scatter","scatter_aggregate_detail","scatter_binned","scatter_binned_color","scatter_binned_size","scatter_bubble","scatter_color","scatter_color_custom","scatter_color_order","scatter_color_ordinal","scatter_color_ordinal_custom","scatter_color_quantitative","scatter_color_shape_constant","scatter_colored_with_shape","scatter_connected","scatter_log","scatter_opacity","square","stacked_area","stacked_area_binned","stacked_area_normalize","stacked_area_ordinal","stacked_area_stream","stacked_bar_1d","stacked_bar_h","stacked_bar_h_order","stacked_bar_normalize","stacked_bar_population","stacked_bar_size","stacked_bar_sum_opacity","stacked_bar_v","stacked_bar_weather","text_scatter_colored","text_table_heatmap","tick_dot","tick_dot_thickness","tick_strip","trellis_anscombe","trellis_bar","trellis_bar_histogram","trellis_barley","trellis_row_column","trellis_scatter","trellis_scatter_binned_row","trellis_stacked_bar"]
{
"description": "Temperature in Seattle as a bar chart with yearmonth time unit.",
"data": {"url": "data/seattle-temps.csv","formatType": "csv"},
"data": {"url": "data/seattle-temps.csv", "format": {"type": "csv"}},
"mark": "bar",

@@ -5,0 +5,0 @@ "encoding": {

@@ -5,3 +5,3 @@ {

"url": "data/gapminder-health-income.csv",
"formatType": "csv"
"format": {"type": "csv"}
},

@@ -8,0 +8,0 @@ "mark": "circle",

{
"data": {"url": "data/stocks.csv","formatType": "csv"},
"data": {"url": "data/stocks.csv","format": {"type": "csv"}},
"layers": [

@@ -4,0 +4,0 @@ {

{
"description": "Stock prices of 5 Tech Companies Over Time.",
"data": {"url": "data/stocks.csv", "formatType":"csv"},
"data": {"url": "data/stocks.csv", "format": {"type": "csv"}},
"mark": "line",

@@ -5,0 +5,0 @@ "encoding": {

{
"description": "Stock prices of 5 Tech Companies Over Time.",
"data": {"url": "data/stocks.csv", "formatType":"csv"},
"data": {"url": "data/stocks.csv", "format": {"type": "csv"}},
"mark": "line",

@@ -5,0 +5,0 @@ "encoding": {

{
"data": {"url": "data/stocks.csv", "formatType":"csv"},
"data": {"url": "data/stocks.csv", "format": {"type": "csv"}},
"transform": {"filter": "datum.symbol==='GOOG'"},

@@ -4,0 +4,0 @@ "mark": "line",

{
"data": {"url": "data/seattle-temps.csv","formatType": "csv"},
"data": {"url": "data/seattle-temps.csv","format": {"type": "csv"}},
"mark": "line",

@@ -4,0 +4,0 @@ "encoding": {

{
"description": "Google's stock price over time.",
"data": {"url": "data/stocks.csv", "formatType":"csv"},
"data": {"url": "data/stocks.csv", "format": {"type": "csv"}},
"transform": {"filter": "datum.symbol==='GOOG'"},

@@ -5,0 +5,0 @@ "mark": "line",

{
"description": "Google's stock price over time.",
"data": {"url": "data/stocks.csv", "formatType":"csv"},
"data": {"url": "data/stocks.csv", "format": {"type": "csv"}},
"transform": {"filter": "datum.symbol==='GOOG'"},

@@ -5,0 +5,0 @@ "mark": "line",

{
"data": {"url": "data/seattle-temps.csv","formatType": "csv"},
"data": {"url": "data/seattle-temps.csv","format": {"type": "csv"}},
"mark": "point",

@@ -4,0 +4,0 @@ "encoding": {

@@ -8,3 +8,4 @@ {

"path": {"field": "year","type": "temporal"}
}
},
"config": {"overlay": {"line": true}}
}
{
"data": {"url": "data/seattle-weather.csv", "formatType": "csv"},
"data": {"url": "data/seattle-weather.csv", "format": {"type": "csv"}},
"mark": "bar",

@@ -4,0 +4,0 @@ "config": {

{
"data": {"url": "data/seattle-weather.csv", "formatType": "csv"},
"data": {"url": "data/seattle-weather.csv","format": {"type": "csv"}},
"mark": "bar",

@@ -4,0 +4,0 @@ "encoding": {

@@ -170,2 +170,17 @@ {

],
"Statistical": [
{
"name": "errorbar_aggregate",
"title": "Error Bars",
"galleryParameters": {
"backgroundSize": "150%"
}
}, {
"name": "errorbar_horizontal_aggregate",
"title": "Horizontal Error Bars",
"galleryParameters": {
"backgroundSize": "150%"
}
}
],
"Trellis": [

@@ -172,0 +187,0 @@ { "name": "trellis_anscombe",

{
"name": "vega-lite",
"author": "Jeffrey Heer, Dominik Moritz, Kanit \"Ham\" Wongsuphasawat",
"version": "1.0.12",
"version": "1.0.13",
"collaborators": [

@@ -68,3 +68,3 @@ "Kanit Wongsuphasawat <kanitw@gmail.com> (http://kanitw.yellowpigz.com)",

"source-map-support": "^0.4.0",
"tsify": "^0.15.5",
"tsify": "^0.16.0",
"tslint": "^3.10.2",

@@ -74,3 +74,3 @@ "typescript": "^1.8.10",

"uglify-js": "^2.6.2",
"vega": "^2.5.2",
"vega": "^2.6.0",
"vega-datasets": "vega/vega-datasets#gh-pages",

@@ -82,3 +82,3 @@ "watchify": "^3.7.0",

"dependencies": {
"datalib": "^1.6.3",
"datalib": "^1.7.0",
"json-stable-stringify": "^1.0.1",

@@ -85,0 +85,0 @@ "yargs": "^4.7.1"

@@ -47,2 +47,7 @@ "use strict";

];
exports.SUM_OPS = [
AggregateOp.COUNT,
AggregateOp.SUM,
AggregateOp.DISTINCT
];
exports.SHARED_DOMAIN_OPS = [

@@ -49,0 +54,0 @@ AggregateOp.MEAN,

@@ -48,2 +48,9 @@

/** Additive-based aggregation operations. These can be applied to stack. */
export const SUM_OPS = [
AggregateOp.COUNT,
AggregateOp.SUM,
AggregateOp.DISTINCT
];
export const SHARED_DOMAIN_OPS = [

@@ -50,0 +57,0 @@ AggregateOp.MEAN,

@@ -6,2 +6,4 @@ "use strict";

Channel[Channel["Y"] = 'y'] = "Y";
Channel[Channel["X2"] = 'x2'] = "X2";
Channel[Channel["Y2"] = 'y2'] = "Y2";
Channel[Channel["ROW"] = 'row'] = "ROW";

@@ -22,2 +24,4 @@ Channel[Channel["COLUMN"] = 'column'] = "COLUMN";

exports.Y = Channel.Y;
exports.X2 = Channel.X2;
exports.Y2 = Channel.Y2;
exports.ROW = Channel.ROW;

@@ -34,7 +38,8 @@ exports.COLUMN = Channel.COLUMN;

exports.OPACITY = Channel.OPACITY;
exports.CHANNELS = [exports.X, exports.Y, exports.ROW, exports.COLUMN, exports.SIZE, exports.SHAPE, exports.COLOR, exports.PATH, exports.ORDER, exports.OPACITY, exports.TEXT, exports.DETAIL, exports.LABEL];
exports.CHANNELS = [exports.X, exports.Y, exports.X2, exports.Y2, exports.ROW, exports.COLUMN, exports.SIZE, exports.SHAPE, exports.COLOR, exports.PATH, exports.ORDER, exports.OPACITY, exports.TEXT, exports.DETAIL, exports.LABEL];
exports.UNIT_CHANNELS = util_1.without(exports.CHANNELS, [exports.ROW, exports.COLUMN]);
exports.UNIT_SCALE_CHANNELS = util_1.without(exports.UNIT_CHANNELS, [exports.PATH, exports.ORDER, exports.DETAIL, exports.TEXT, exports.LABEL]);
exports.NONSPATIAL_CHANNELS = util_1.without(exports.UNIT_CHANNELS, [exports.X, exports.Y]);
exports.NONSPATIAL_SCALE_CHANNELS = util_1.without(exports.UNIT_SCALE_CHANNELS, [exports.X, exports.Y]);
exports.UNIT_SCALE_CHANNELS = util_1.without(exports.UNIT_CHANNELS, [exports.PATH, exports.ORDER, exports.DETAIL, exports.TEXT, exports.LABEL, exports.X2, exports.Y2]);
exports.NONSPATIAL_CHANNELS = util_1.without(exports.UNIT_CHANNELS, [exports.X, exports.Y, exports.X2, exports.Y2]);
exports.NONSPATIAL_SCALE_CHANNELS = util_1.without(exports.UNIT_SCALE_CHANNELS, [exports.X, exports.Y, exports.X2, exports.Y2]);
exports.STACK_GROUP_CHANNELS = [exports.COLOR, exports.DETAIL, exports.ORDER, exports.OPACITY, exports.SIZE];
;

@@ -59,2 +64,7 @@ function supportMark(channel, mark) {

};
case exports.X2:
case exports.Y2:
return {
rule: true, bar: true, area: true
};
case exports.SIZE:

@@ -95,2 +105,4 @@ return {

};
case exports.X2:
case exports.Y2:
case exports.SIZE:

@@ -97,0 +109,0 @@ case exports.TEXT:

@@ -12,2 +12,4 @@ /*

Y = 'y' as any,
X2 = 'x2' as any,
Y2 = 'y2' as any,
ROW = 'row' as any,

@@ -28,2 +30,4 @@ COLUMN = 'column' as any,

export const Y = Channel.Y;
export const X2 = Channel.X2;
export const Y2 = Channel.Y2;
export const ROW = Channel.ROW;

@@ -41,9 +45,12 @@ export const COLUMN = Channel.COLUMN;

export const CHANNELS = [X, Y, ROW, COLUMN, SIZE, SHAPE, COLOR, PATH, ORDER, OPACITY, TEXT, DETAIL, LABEL];
export const CHANNELS = [X, Y, X2, Y2, ROW, COLUMN, SIZE, SHAPE, COLOR, PATH, ORDER, OPACITY, TEXT, DETAIL, LABEL];
export const UNIT_CHANNELS = without(CHANNELS, [ROW, COLUMN]);
export const UNIT_SCALE_CHANNELS = without(UNIT_CHANNELS, [PATH, ORDER, DETAIL, TEXT, LABEL]);
export const NONSPATIAL_CHANNELS = without(UNIT_CHANNELS, [X, Y]);
export const NONSPATIAL_SCALE_CHANNELS = without(UNIT_SCALE_CHANNELS, [X, Y]);
export const UNIT_SCALE_CHANNELS = without(UNIT_CHANNELS, [PATH, ORDER, DETAIL, TEXT, LABEL, X2, Y2]);
export const NONSPATIAL_CHANNELS = without(UNIT_CHANNELS, [X, Y, X2, Y2]);
export const NONSPATIAL_SCALE_CHANNELS = without(UNIT_SCALE_CHANNELS, [X, Y, X2, Y2]);
/** Channels that can serve as groupings for stacked charts. */
export const STACK_GROUP_CHANNELS = [COLOR, DETAIL, ORDER, OPACITY, SIZE];
export interface SupportedMark {

@@ -90,2 +97,7 @@ point?: boolean;

};
case X2:
case Y2:
return {
rule: true, bar: true, area: true
};
case SIZE:

@@ -135,2 +147,4 @@ return {

};
case X2:
case Y2:
case SIZE:

@@ -137,0 +151,0 @@ case TEXT:

@@ -63,5 +63,4 @@ "use strict";

};
util_1.extend(def, common_1.formatMixins(model, channel, model.axis(channel).format));
[
'grid', 'layer', 'offset', 'orient', 'tickSize', 'ticks', 'tickSizeEnd', 'title', 'titleOffset',
'format', 'grid', 'layer', 'offset', 'orient', 'tickSize', 'ticks', 'tickSizeEnd', 'title', 'titleOffset',
'tickPadding', 'tickSize', 'tickSizeMajor', 'tickSizeMinor', 'values', 'subdivide'

@@ -93,2 +92,6 @@ ].forEach(function (property) {

exports.parseAxis = parseAxis;
function format(model, channel) {
return common_1.numberFormat(model.fieldDef(channel), model.axis(channel).format, model.config());
}
exports.format = format;
function offset(model, channel) {

@@ -211,2 +214,3 @@ return model.axis(channel).offset;

var axis = model.axis(channel);
var config = model.config();
if (!axis.labels) {

@@ -220,6 +224,13 @@ return util_1.extend({

text: {
template: '{{ datum.data | truncate:' + axis.labelMaxLength + '}}'
template: '{{ datum.data | truncate:' + axis.labelMaxLength + ' }}'
}
}, labelsSpec || {});
}
else if (fieldDef.type === type_1.TEMPORAL) {
labelsSpec = util_1.extend({
text: {
template: common_1.timeTemplate('datum.data', fieldDef.timeUnit, axis.format, axis.shortTimeLabels, config)
}
}, labelsSpec);
}
if (axis.labelAngle !== undefined) {

@@ -226,0 +237,0 @@ labelsSpec.angle = { value: axis.labelAngle };

@@ -8,3 +8,3 @@ import {AxisOrient} from '../axis';

import {formatMixins} from './common';
import {numberFormat, timeTemplate} from './common';
import {Model} from './model';

@@ -95,9 +95,6 @@ import {UnitModel} from './unit';

// format mixins (add format and formatType)
extend(def, formatMixins(model, channel, model.axis(channel).format));
// 1.2. Add properties
[
// a) properties with special rules (so it has axis[property] methods) -- call rule functions
'grid', 'layer', 'offset', 'orient', 'tickSize', 'ticks', 'tickSizeEnd', 'title', 'titleOffset',
'format', 'grid', 'layer', 'offset', 'orient', 'tickSize', 'ticks', 'tickSizeEnd', 'title', 'titleOffset',
// b) properties without rules, only produce default values in the schema, or explicit value if specified

@@ -136,2 +133,6 @@ 'tickPadding', 'tickSize', 'tickSizeMajor', 'tickSizeMinor', 'values', 'subdivide'

export function format(model: Model, channel: Channel) {
return numberFormat(model.fieldDef(channel), model.axis(channel).format, model.config());
}
export function offset(model: Model, channel: Channel) {

@@ -287,2 +288,3 @@ return model.axis(channel).offset;

const axis = model.axis(channel);
const config = model.config();

@@ -295,2 +297,3 @@ if (!axis.labels) {

// Text
if (contains([NOMINAL, ORDINAL], fieldDef.type) && axis.labelMaxLength) {

@@ -300,5 +303,11 @@ // TODO replace this with Vega's labelMaxLength once it is introduced

text: {
template: '{{ datum.data | truncate:' + axis.labelMaxLength + '}}'
template: '{{ datum.data | truncate:' + axis.labelMaxLength + ' }}'
}
}, labelsSpec || {});
} else if (fieldDef.type === TEMPORAL) {
labelsSpec = extend({
text: {
template: timeTemplate('datum.data', fieldDef.timeUnit, axis.format, axis.shortTimeLabels, config)
}
}, labelsSpec);
}

@@ -305,0 +314,0 @@

@@ -92,62 +92,23 @@ "use strict";

exports.applyMarkConfig = applyMarkConfig;
function formatMixins(model, channel, format) {
var fieldDef = model.fieldDef(channel);
if (!util_1.contains([type_1.QUANTITATIVE, type_1.TEMPORAL], fieldDef.type)) {
return {};
function numberFormat(fieldDef, format, config) {
if (fieldDef.type === type_1.QUANTITATIVE && !fieldDef.bin) {
return format || config.numberFormat;
}
var def = {};
if (fieldDef.type === type_1.TEMPORAL) {
def.formatType = 'time';
}
if (format !== undefined) {
def.format = format;
}
else {
switch (fieldDef.type) {
case type_1.QUANTITATIVE:
def.format = model.config().numberFormat;
break;
case type_1.TEMPORAL:
def.format = timeFormat(model, channel) || model.config().timeFormat;
break;
}
}
if (channel === channel_1.TEXT) {
var filter = (def.formatType || 'number') + (def.format ? ':\'' + def.format + '\'' : '');
return {
text: {
template: '{{' + model.field(channel, { datum: true }) + ' | ' + filter + '}}'
}
};
}
return def;
return undefined;
}
exports.formatMixins = formatMixins;
function isAbbreviated(model, channel, fieldDef) {
switch (channel) {
case channel_1.ROW:
case channel_1.COLUMN:
case channel_1.X:
case channel_1.Y:
return model.axis(channel).shortTimeLabels;
case channel_1.COLOR:
case channel_1.OPACITY:
case channel_1.SHAPE:
case channel_1.SIZE:
return model.legend(channel).shortTimeLabels;
case channel_1.TEXT:
return model.config().mark.shortTimeLabels;
case channel_1.LABEL:
}
return false;
}
exports.numberFormat = numberFormat;
function sortField(orderChannelDef) {
return (orderChannelDef.sort === sort_1.SortOrder.DESCENDING ? '-' : '') + fielddef_1.field(orderChannelDef);
return (orderChannelDef.sort === sort_1.SortOrder.DESCENDING ? '-' : '') +
fielddef_1.field(orderChannelDef, { binSuffix: '_mid' });
}
exports.sortField = sortField;
function timeFormat(model, channel) {
var fieldDef = model.fieldDef(channel);
return timeunit_1.format(fieldDef.timeUnit, isAbbreviated(model, channel, fieldDef));
function timeTemplate(templateField, timeUnit, format, shortTimeLabels, config) {
if (!timeUnit || format) {
return '{{' + templateField + ' | time:\'' + (format || config.timeFormat) + '\'}}';
}
else {
return timeunit_1.template(timeUnit, templateField, shortTimeLabels);
}
}
exports.timeFormat = timeFormat;
exports.timeTemplate = timeTemplate;
//# sourceMappingURL=common.js.map

@@ -1,6 +0,8 @@

import {COLUMN, ROW, X, Y, SIZE, COLOR, OPACITY, SHAPE, TEXT, LABEL, Channel} from '../channel';
import {COLOR, OPACITY} from '../channel';
import {Config} from '../config';
import {FieldDef, field, OrderChannelDef} from '../fielddef';
import {SortOrder} from '../sort';
import {QUANTITATIVE, ORDINAL, TEMPORAL} from '../type';
import {contains, union} from '../util';
import {TimeUnit} from '../timeunit';
import {QUANTITATIVE, ORDINAL} from '../type';
import { union} from '../util';

@@ -10,3 +12,3 @@ import {FacetModel} from './facet';

import {Model} from './model';
import {format as timeFormatExpr} from '../timeunit';
import {template as timeUnitTemplate} from '../timeunit';
import {UnitModel} from './unit';

@@ -106,82 +108,31 @@ import {Spec, isUnitSpec, isFacetSpec, isLayerSpec} from '../spec';

/**
* Builds an object with format and formatType properties.
* Returns number format for a fieldDef
*
* @param format explicitly specified format
*/
export function formatMixins(model: Model, channel: Channel, format: string) {
const fieldDef = model.fieldDef(channel);
if(!contains([QUANTITATIVE, TEMPORAL], fieldDef.type)) {
return {};
export function numberFormat(fieldDef: FieldDef, format: string, config: Config) {
if (fieldDef.type === QUANTITATIVE && !fieldDef.bin) {
// add number format for quantitative type only
// TODO: need to make this work correctly for numeric ordinal / nominal type
return format || config.numberFormat;
}
let def: any = {};
if (fieldDef.type === TEMPORAL) {
def.formatType = 'time';
}
if (format !== undefined) {
def.format = format;
} else {
switch (fieldDef.type) {
case QUANTITATIVE:
def.format = model.config().numberFormat;
break;
case TEMPORAL:
def.format = timeFormat(model, channel) || model.config().timeFormat;
break;
}
}
if (channel === TEXT) {
// text does not support format and formatType
// https://github.com/vega/vega/issues/505
const filter = (def.formatType || 'number') + (def.format ? ':\'' + def.format + '\'' : '');
return {
text: {
template: '{{' + model.field(channel, { datum: true }) + ' | ' + filter + '}}'
}
};
}
return def;
return undefined;
}
function isAbbreviated(model: Model, channel: Channel, fieldDef: FieldDef) {
switch (channel) {
case ROW:
case COLUMN:
case X:
case Y:
return model.axis(channel).shortTimeLabels;
case COLOR:
case OPACITY:
case SHAPE:
case SIZE:
return model.legend(channel).shortTimeLabels;
case TEXT:
return model.config().mark.shortTimeLabels;
case LABEL:
// TODO(#897): implement when we have label
}
return false;
}
/** Return field reference with potential "-" prefix for descending sort */
export function sortField(orderChannelDef: OrderChannelDef) {
return (orderChannelDef.sort === SortOrder.DESCENDING ? '-' : '') + field(orderChannelDef);
return (orderChannelDef.sort === SortOrder.DESCENDING ? '-' : '') +
field(orderChannelDef, {binSuffix: '_mid'});
}
/**
* Returns the time format used for axis labels for a time unit.
* Returns the time template used for axis/legend labels or text mark for a temporal field
*/
export function timeFormat(model: Model, channel: Channel): string {
const fieldDef = model.fieldDef(channel);
return timeFormatExpr(fieldDef.timeUnit, isAbbreviated(model, channel, fieldDef));
export function timeTemplate(templateField: string, timeUnit: TimeUnit, format: string, shortTimeLabels: boolean, config: Config): string {
if (!timeUnit || format) {
return '{{' + templateField + ' | time:\'' + (format || config.timeFormat) + '\'}}';
} else {
return timeUnitTemplate(timeUnit, templateField, shortTimeLabels);
}
}

@@ -17,4 +17,9 @@ "use strict";

case 'opacity':
if (value === undefined && util_1.contains([mark_1.POINT, mark_1.TICK, mark_1.CIRCLE, mark_1.SQUARE], mark)) {
if (!encoding_1.isAggregate(encoding) || encoding_1.has(encoding, channel_1.DETAIL)) {
if (value === undefined) {
if (util_1.contains([mark_1.POINT, mark_1.TICK, mark_1.CIRCLE, mark_1.SQUARE], mark)) {
if (!encoding_1.isAggregate(encoding) || encoding_1.has(encoding, channel_1.DETAIL)) {
cfg[property] = 0.7;
}
}
if (mark === mark_1.AREA) {
cfg[property] = 0.7;

@@ -25,4 +30,4 @@ }

case 'orient':
var xIsMeasure = fielddef_1.isMeasure(encoding.x);
var yIsMeasure = fielddef_1.isMeasure(encoding.y);
var xIsMeasure = fielddef_1.isMeasure(encoding.x) || fielddef_1.isMeasure(encoding.x2);
var yIsMeasure = fielddef_1.isMeasure(encoding.y) || fielddef_1.isMeasure(encoding.y2);
if (xIsMeasure && !yIsMeasure) {

@@ -29,0 +34,0 @@ if (mark === mark_1.TICK) {

@@ -6,3 +6,3 @@ import {X, DETAIL} from '../channel';

import {isMeasure} from '../fielddef';
import {POINT, LINE, TICK, CIRCLE, SQUARE, RULE, Mark} from '../mark';
import {AREA, POINT, LINE, TICK, CIRCLE, SQUARE, RULE, Mark} from '../mark';
import {contains, extend} from '../util';

@@ -25,12 +25,17 @@

case 'opacity':
if (value === undefined && contains([POINT, TICK, CIRCLE, SQUARE], mark)) {
// point-based marks and bar
if (!isAggregate(encoding) || has(encoding, DETAIL)) {
cfg[property] = 0.7;
}
if (value === undefined) {
if (contains([POINT, TICK, CIRCLE, SQUARE], mark)) {
// point-based marks and bar
if (!isAggregate(encoding) || has(encoding, DETAIL)) {
cfg[property] = 0.7;
}
}
if (mark === AREA) {
cfg[property] = 0.7; // inspired by Tableau
}
}
break;
case 'orient':
const xIsMeasure = isMeasure(encoding.x);
const yIsMeasure = isMeasure(encoding.y);
const xIsMeasure = isMeasure(encoding.x) || isMeasure(encoding.x2);
const yIsMeasure = isMeasure(encoding.y) || isMeasure(encoding.y2);

@@ -40,5 +45,5 @@ // When unambiguous, do not allow overriding

if (mark === TICK) {
cfg[property] = 'vertical'; // implicitly vertical
cfg[property] = 'vertical';
} else {
cfg[property] = 'horizontal'; // implicitly horizontal
cfg[property] = 'horizontal';
}

@@ -45,0 +50,0 @@ } else if (!xIsMeasure && yIsMeasure) {

@@ -22,6 +22,12 @@ "use strict";

var defaultExtension = /(?:\.([^.]+))?$/.exec(sourceData.url)[1];
if (!util_1.contains(['json', 'csv', 'tsv'], defaultExtension)) {
if (!util_1.contains(['json', 'csv', 'tsv', 'topojson'], defaultExtension)) {
defaultExtension = 'json';
}
sourceData.format = { type: model.data().formatType || defaultExtension };
var dataFormat = model.data().format || {};
sourceData.format =
util_1.extend({ type: dataFormat.type ? model.data().format.type : defaultExtension }, dataFormat.property ? { property: dataFormat.property } : {}, dataFormat.feature ?
{ feature: dataFormat.feature } :
dataFormat.mesh ?
{ mesh: dataFormat.mesh } :
{});
}

@@ -28,0 +34,0 @@ return sourceData;

@@ -1,7 +0,7 @@

import {SOURCE} from '../../data';
import {contains} from '../../util';
import {DataFormat, SOURCE} from '../../data';
import {contains, extend} from '../../util';
import {VgData} from '../../vega.schema';
import {FacetModel} from './../facet';
import {LayerModel} from './../layer';
import {FacetModel} from '../facet';
import {LayerModel} from '../layer';
import {Model} from './../model';

@@ -33,6 +33,17 @@

let defaultExtension = /(?:\.([^.]+))?$/.exec(sourceData.url)[1];
if (!contains(['json', 'csv', 'tsv'], defaultExtension)) {
if (!contains(['json', 'csv', 'tsv', 'topojson'], defaultExtension)) {
defaultExtension = 'json';
}
sourceData.format = { type: model.data().formatType || defaultExtension };
const dataFormat: DataFormat = model.data().format || {};
sourceData.format =
extend(
{ type: dataFormat.type ? model.data().format.type : defaultExtension },
dataFormat.property ? { property: dataFormat.property } : {},
// Feature and mesh are two mutually exclusive properties
dataFormat.feature ?
{ feature : dataFormat.feature } :
dataFormat.mesh ?
{ mesh : dataFormat.mesh } :
{}
);
}

@@ -39,0 +50,0 @@ return sourceData;

@@ -57,3 +57,3 @@ "use strict";

function unitSizeExpr(model, channel, nonOrdinalSize) {
if (model.has(channel)) {
if (model.scale(channel)) {
if (model.isOrdinalScale(channel)) {

@@ -60,0 +60,0 @@ var scale = model.scale(channel);

@@ -89,3 +89,3 @@

function unitSizeExpr(model: UnitModel, channel: Channel, nonOrdinalSize: number): string {
if (model.has(channel)) {
if (model.scale(channel)) {
if (model.isOrdinalScale(channel)) {

@@ -92,0 +92,0 @@ const scale = model.scale(channel);

@@ -36,7 +36,10 @@ "use strict";

var legend = model.legend(channel);
var config = model.config();
var def = getLegendDefWithScale(model, channel);
def.title = title(legend, fieldDef);
def.offset = offset(legend, fieldDef);
util_1.extend(def, formatMixins(legend, model, channel));
['orient', 'values'].forEach(function (property) {
var format = common_1.numberFormat(fieldDef, legend.format, config);
if (format) {
def.format = format;
}
['offset', 'orient', 'values'].forEach(function (property) {
var value = legend[property];

@@ -60,17 +63,2 @@ if (value !== undefined) {

exports.parseLegend = parseLegend;
function offset(legend, fieldDef) {
if (legend.offset !== undefined) {
return legend.offset;
}
return 0;
}
exports.offset = offset;
function orient(legend, fieldDef) {
var orient = legend.orient;
if (orient) {
return orient;
}
return 'vertical';
}
exports.orient = orient;
function title(legend, fieldDef) {

@@ -83,10 +71,2 @@ if (typeof legend !== 'boolean' && legend.title) {

exports.title = title;
function formatMixins(legend, model, channel) {
var fieldDef = model.fieldDef(channel);
if (fieldDef.bin) {
return {};
}
return common_1.formatMixins(model, channel, typeof legend !== 'boolean' ? legend.format : undefined);
}
exports.formatMixins = formatMixins;
function useColorLegendScale(fieldDef) {

@@ -165,2 +145,3 @@ return fieldDef.type === type_1.ORDINAL || fieldDef.bin || fieldDef.timeUnit;

var legend = model.legend(channel);
var config = model.config();
var labels = {};

@@ -184,6 +165,6 @@ if (channel === channel_1.COLOR) {

}
else if (fieldDef.timeUnit) {
else if (fieldDef.type === type_1.TEMPORAL) {
labelsSpec = util_1.extend({
text: {
template: '{{ datum.data | time:\'' + common_1.timeFormat(model, channel) + '\'}}'
template: common_1.timeTemplate('datum.data', fieldDef.timeUnit, legend.format, legend.shortTimeLabels, config)
}

@@ -190,0 +171,0 @@ }, labelsSpec || {});

@@ -6,6 +6,6 @@ import {COLOR, SIZE, SHAPE, Channel} from '../channel';

import {AREA, BAR, TICK, TEXT, LINE, POINT, CIRCLE, SQUARE} from '../mark';
import {ORDINAL} from '../type';
import {ORDINAL, TEMPORAL} from '../type';
import {extend, keys, without, Dict} from '../util';
import {applyMarkConfig, FILL_STROKE_CONFIG, formatMixins as utilFormatMixins, timeFormat} from './common';
import {applyMarkConfig, FILL_STROKE_CONFIG, numberFormat, timeTemplate} from './common';
import {COLOR_LEGEND, COLOR_LEGEND_LABEL} from './scale';

@@ -50,2 +50,3 @@ import {UnitModel} from './unit';

const legend = model.legend(channel);
const config = model.config();

@@ -56,9 +57,9 @@ let def: VgLegend = getLegendDefWithScale(model, channel);

def.title = title(legend, fieldDef);
const format = numberFormat(fieldDef, legend.format, config);
if (format) {
def.format = format;
}
def.offset = offset(legend, fieldDef);
extend(def, formatMixins(legend, model, channel));
// 1.2 Add properties without rules
['orient', 'values'].forEach(function(property) {
['offset', 'orient', 'values'].forEach(function(property) {
const value = legend[property];

@@ -85,17 +86,2 @@ if (value !== undefined) {

export function offset(legend: Legend, fieldDef: FieldDef) {
if (legend.offset !== undefined) {
return legend.offset;
}
return 0;
}
export function orient(legend: Legend, fieldDef: FieldDef) {
const orient = legend.orient;
if (orient) {
return orient;
}
return 'vertical';
}
export function title(legend: Legend, fieldDef: FieldDef) {

@@ -109,13 +95,2 @@ if (typeof legend !== 'boolean' && legend.title) {

export function formatMixins(legend: Legend, model: UnitModel, channel: Channel) {
const fieldDef = model.fieldDef(channel);
// If the channel is binned, we should not set the format because we have a range label
if (fieldDef.bin) {
return {};
}
return utilFormatMixins(model, channel, typeof legend !== 'boolean' ? legend.format : undefined);
}
// we have to use special scales for ordinal or binned fields for the color channel

@@ -213,2 +188,3 @@ export function useColorLegendScale(fieldDef: FieldDef) {

const legend = model.legend(channel);
const config = model.config();

@@ -232,6 +208,6 @@ let labels:any = {};

}, labelsSpec || {});
} else if (fieldDef.timeUnit) {
} else if (fieldDef.type === TEMPORAL) {
labelsSpec = extend({
text: {
template: '{{ datum.data | time:\'' + timeFormat(model, channel) + '\'}}'
template: timeTemplate('datum.data', fieldDef.timeUnit, legend.format, legend.shortTimeLabels, config)
}

@@ -238,0 +214,0 @@ }, labelsSpec || {});

@@ -7,3 +7,3 @@ import {UnitModel} from '../unit';

import {applyColorAndOpacity, applyMarkConfig} from '../common';
import {StackProperties} from '../stack';
import {StackProperties} from '../../stack';

@@ -10,0 +10,0 @@ export namespace area {

@@ -16,2 +16,4 @@ "use strict";

var xFieldDef = model.encoding().x;
var x2FieldDef = model.encoding().x2;
var xIsMeasure = fielddef_1.isMeasure(xFieldDef) || fielddef_1.isMeasure(x2FieldDef);
if (stack && channel_1.X === stack.fieldChannel) {

@@ -27,12 +29,28 @@ p.x = {

}
else if (fielddef_1.isMeasure(xFieldDef)) {
else if (xIsMeasure) {
if (orient === 'horizontal') {
p.x = {
scale: model.scaleName(channel_1.X),
field: model.field(channel_1.X)
};
p.x2 = {
scale: model.scaleName(channel_1.X),
value: 0
};
if (model.has(channel_1.X)) {
p.x = {
scale: model.scaleName(channel_1.X),
field: model.field(channel_1.X)
};
}
else {
p.x = {
scale: model.scaleName(channel_1.X),
value: 0
};
}
if (model.has(channel_1.X2)) {
p.x2 = {
scale: model.scaleName(channel_1.X),
field: model.field(channel_1.X2)
};
}
else {
p.x2 = {
scale: model.scaleName(channel_1.X),
value: 0
};
}
}

@@ -88,2 +106,4 @@ else {

var yFieldDef = model.encoding().y;
var y2FieldDef = model.encoding().y2;
var yIsMeasure = fielddef_1.isMeasure(yFieldDef) || fielddef_1.isMeasure(y2FieldDef);
if (stack && channel_1.Y === stack.fieldChannel) {

@@ -99,12 +119,28 @@ p.y = {

}
else if (fielddef_1.isMeasure(yFieldDef)) {
else if (yIsMeasure) {
if (orient !== 'horizontal') {
p.y = {
scale: model.scaleName(channel_1.Y),
field: model.field(channel_1.Y)
};
p.y2 = {
scale: model.scaleName(channel_1.Y),
value: 0
};
if (model.has(channel_1.Y)) {
p.y = {
scale: model.scaleName(channel_1.Y),
field: model.field(channel_1.Y)
};
}
else {
p.y = {
scale: model.scaleName(channel_1.Y),
value: 0
};
}
if (model.has(channel_1.Y2)) {
p.y2 = {
scale: model.scaleName(channel_1.Y),
field: model.field(channel_1.Y2)
};
}
else {
p.y2 = {
scale: model.scaleName(channel_1.Y),
value: 0
};
}
}

@@ -111,0 +147,0 @@ else {

@@ -1,2 +0,2 @@

import {X, Y, SIZE, Channel} from '../../channel';
import {X, Y, X2, Y2, SIZE, Channel} from '../../channel';
import {isMeasure} from '../../fielddef';

@@ -20,2 +20,6 @@

const xFieldDef = model.encoding().x;
const x2FieldDef = model.encoding().x2;
const xIsMeasure = isMeasure(xFieldDef) || isMeasure(x2FieldDef);
// x, x2, and width -- we must specify two of these in all conditions

@@ -32,12 +36,27 @@ if (stack && X === stack.fieldChannel) {

};
} else if (isMeasure(xFieldDef)) {
} else if (xIsMeasure) {
if (orient === 'horizontal') {
p.x = {
scale: model.scaleName(X),
field: model.field(X)
};
p.x2 = {
scale: model.scaleName(X),
value: 0
};
if (model.has(X)) {
p.x = {
scale: model.scaleName(X),
field: model.field(X)
};
} else {
p.x = {
scale: model.scaleName(X),
value: 0
};
}
if (model.has(X2)) {
p.x2 = {
scale: model.scaleName(X),
field: model.field(X2)
};
} else {
p.x2 = {
scale: model.scaleName(X),
value: 0
};
}
} else { // vertical

@@ -94,2 +113,5 @@ p.xc = {

const yFieldDef = model.encoding().y;
const y2FieldDef = model.encoding().y2;
const yIsMeasure = isMeasure(yFieldDef) || isMeasure(y2FieldDef);
// y, y2 & height -- we must specify two of these in all conditions

@@ -105,12 +127,27 @@ if (stack && Y === stack.fieldChannel) { // y is stacked measure

};
} else if (isMeasure(yFieldDef)) {
} else if (yIsMeasure) {
if (orient !== 'horizontal') { // vertical (explicit 'vertical' or undefined)
p.y = {
scale: model.scaleName(Y),
field: model.field(Y)
};
p.y2 = {
scale: model.scaleName(Y),
value: 0
};
if (model.has(Y)) {
p.y = {
scale: model.scaleName(Y),
field: model.field(Y)
};
} else {
p.y = {
scale: model.scaleName(Y),
value: 0
};
}
if (model.has(Y2)) {
p.y2 = {
scale: model.scaleName(Y),
field: model.field(Y2)
};
} else {
p.y2 = {
scale: model.scaleName(Y),
value: 0
};
}
} else {

@@ -117,0 +154,0 @@ p.yc = {

"use strict";
var channel_1 = require('../../channel');
var encoding_1 = require('../../encoding');
var fielddef_1 = require('../../fielddef');
var mark_1 = require('../../mark');
var stack_1 = require('../stack');
var scale_1 = require('../../scale');
var util_1 = require('../../util');
var area_1 = require('./area');
var bar_1 = require('./bar');
var common_1 = require('../common');
var line_1 = require('./line');
var point_1 = require('./point');
var rule_1 = require('./rule');
var text_1 = require('./text');
var tick_1 = require('./tick');
var rule_1 = require('./rule');
var common_1 = require('../common');
var markCompiler = {

@@ -50,3 +52,3 @@ area: area_1.area,

var transform = mark === mark_1.AREA && model.stack() ?
[stack_1.imputeTransform(model), stack_1.stackTransform(model), facetTransform] :
stackTransforms(model, true).concat(facetTransform) :
[].concat(facetTransform, model.has(channel_1.ORDER) ? [{ type: 'sort', by: sortBy(model) }] : []);

@@ -88,3 +90,3 @@ return [{

from: util_1.extend(isFaceted ? {} : dataFrom, model.stack() ?
{ transform: [stack_1.stackTransform(model)] } :
{ transform: stackTransforms(model, false) } :
model.has(channel_1.ORDER) ?

@@ -128,3 +130,3 @@ { transform: [{ type: 'sort', by: sortBy(model) }] } :

else {
return '-' + model.field(model.config().mark.orient === 'horizontal' ? channel_1.Y : channel_1.X);
return '-' + model.field(model.config().mark.orient === 'horizontal' ? channel_1.Y : channel_1.X, { binSuffix: '_mid' });
}

@@ -140,2 +142,65 @@ }

}
function stackTransforms(model, impute) {
var stackByFields = getStackByFields(model);
if (impute) {
return [imputeTransform(model, stackByFields), stackTransform(model, stackByFields)];
}
return [stackTransform(model, stackByFields)];
}
function getStackByFields(model) {
var encoding = model.encoding();
return channel_1.STACK_GROUP_CHANNELS.reduce(function (fields, channel) {
var channelEncoding = encoding[channel];
if (encoding_1.has(encoding, channel)) {
if (util_1.isArray(channelEncoding)) {
channelEncoding.forEach(function (fieldDef) {
fields.push(fielddef_1.field(fieldDef));
});
}
else {
var fieldDef = channelEncoding;
var scale = model.scale(channel);
fields.push(fielddef_1.field(fieldDef, {
binSuffix: scale && scale.type === scale_1.ScaleType.ORDINAL ? '_range' : '_start'
}));
}
}
return fields;
}, []);
}
function imputeTransform(model, stackFields) {
var stack = model.stack();
return {
type: 'impute',
field: model.field(stack.fieldChannel),
groupby: stackFields,
orderby: [model.field(stack.groupbyChannel, { binSuffix: '_mid' })],
method: 'value',
value: 0
};
}
function stackTransform(model, stackFields) {
var stack = model.stack();
var encoding = model.encoding();
var sortby = model.has(channel_1.ORDER) ?
(util_1.isArray(encoding[channel_1.ORDER]) ? encoding[channel_1.ORDER] : [encoding[channel_1.ORDER]]).map(common_1.sortField) :
stackFields.map(function (field) {
return '-' + field;
});
var valName = model.field(stack.fieldChannel);
var transform = {
type: 'stack',
groupby: [model.field(stack.groupbyChannel, { binSuffix: '_mid' })],
field: model.field(stack.fieldChannel),
sortby: sortby,
output: {
start: valName + '_start',
end: valName + '_end'
}
};
if (stack.offset) {
transform.offset = stack.offset;
}
return transform;
}
//# sourceMappingURL=mark.js.map

@@ -1,16 +0,18 @@

import {UnitModel} from '../unit';
import {OrderChannelDef} from '../../fielddef';
import {X, Y, COLOR, TEXT, SHAPE, PATH, ORDER, OPACITY, DETAIL, LABEL, STACK_GROUP_CHANNELS} from '../../channel';
import {has} from '../../encoding';
import {OrderChannelDef, FieldDef, field} from '../../fielddef';
import {AREA, LINE, TEXT as TEXTMARK} from '../../mark';
import {ScaleType} from '../../scale';
import {contains, extend, isArray} from '../../util';
import {VgStackTransform} from '../../vega.schema';
import {X, Y, COLOR, TEXT, SHAPE, PATH, ORDER, OPACITY, DETAIL, LABEL} from '../../channel';
import {AREA, LINE, TEXT as TEXTMARK} from '../../mark';
import {imputeTransform, stackTransform} from '../stack';
import {contains, extend} from '../../util';
import {area} from './area';
import {bar} from './bar';
import {sortField} from '../common';
import {line} from './line';
import {point, circle, square} from './point';
import {rule} from './rule';
import {text} from './text';
import {tick} from './tick';
import {rule} from './rule';
import {sortField} from '../common';
import {UnitModel} from '../unit';

@@ -66,3 +68,3 @@ const markCompiler = {

// (Mark layer order does not matter for stacked charts)
[imputeTransform(model), stackTransform(model), facetTransform] :
stackTransforms(model, true).concat(facetTransform) :
// For non-stacked path (line/area), we need to facet and possibly sort

@@ -134,3 +136,3 @@ [].concat(

model.stack() ? // Stacked Chart need stack transform
{ transform: [stackTransform(model)] } :
{ transform: stackTransforms(model, false) } :
model.has(ORDER) ?

@@ -199,3 +201,3 @@ // if non-stacked, detail field determines the layer order of each mark

// For both line and area, we sort values based on dimension by default
return '-' + model.field(model.config().mark.orient === 'horizontal' ? Y : X);
return '-' + model.field(model.config().mark.orient === 'horizontal' ? Y : X, {binSuffix: '_mid'});
}

@@ -216,1 +218,77 @@ }

}
function stackTransforms(model: UnitModel, impute: boolean): any[] {
const stackByFields = getStackByFields(model);
if (impute) {
return [imputeTransform(model, stackByFields), stackTransform(model, stackByFields)];
}
return [stackTransform(model, stackByFields)];
}
/** Compile stack-by field names from (from 'color' and 'detail') */
function getStackByFields(model: UnitModel) {
const encoding = model.encoding();
return STACK_GROUP_CHANNELS.reduce(function(fields, channel) {
const channelEncoding = encoding[channel];
if (has(encoding, channel)) {
if (isArray(channelEncoding)) {
channelEncoding.forEach(function(fieldDef) {
fields.push(field(fieldDef));
});
} else {
const fieldDef: FieldDef = channelEncoding;
const scale = model.scale(channel);
fields.push(field(fieldDef, {
binSuffix: scale && scale.type === ScaleType.ORDINAL ? '_range' : '_start'
}));
}
}
return fields;
}, []);
}
// impute data for stacked area
function imputeTransform(model: UnitModel, stackFields: string[]) {
const stack = model.stack();
return {
type: 'impute',
field: model.field(stack.fieldChannel),
groupby: stackFields,
orderby: [model.field(stack.groupbyChannel, {binSuffix: '_mid'})],
method: 'value',
value: 0
};
}
function stackTransform(model: UnitModel, stackFields: string[]) {
const stack = model.stack();
const encoding = model.encoding();
const sortby = model.has(ORDER) ?
(isArray(encoding[ORDER]) ? encoding[ORDER] : [encoding[ORDER]]).map(sortField) :
// default = descending by stackFields
stackFields.map(function(field) {
return '-' + field;
});
const valName = model.field(stack.fieldChannel);
// add stack transform to mark
let transform: VgStackTransform = {
type: 'stack',
groupby: [model.field(stack.groupbyChannel, {binSuffix: '_mid'})],
field: model.field(stack.fieldChannel),
sortby: sortby,
output: {
start: valName + '_start',
end: valName + '_end'
}
};
if (stack.offset) {
transform.offset = stack.offset;
}
return transform;
}

@@ -12,15 +12,59 @@ "use strict";

var p = {};
if (model.has(channel_1.X)) {
p.x = position(model, channel_1.X);
p.y = { value: 0 };
p.y2 = {
field: { group: 'height' }
};
if (model.config().mark.orient === 'vertical') {
if (model.has(channel_1.X)) {
p.x = {
scale: model.scaleName(channel_1.X),
field: model.field(channel_1.X, { binSuffix: '_mid' })
};
}
else {
p.x = { value: 0 };
}
if (model.has(channel_1.Y)) {
p.y = {
scale: model.scaleName(channel_1.Y),
field: model.field(channel_1.Y, { binSuffix: '_mid' })
};
}
else {
p.y = { field: { group: 'height' } };
}
if (model.has(channel_1.Y2)) {
p.y2 = {
scale: model.scaleName(channel_1.Y),
field: model.field(channel_1.Y2, { binSuffix: '_mid' })
};
}
else {
p.y2 = { value: 0 };
}
}
if (model.has(channel_1.Y)) {
p.y = position(model, channel_1.Y);
p.x = { value: 0 };
p.x2 = {
field: { group: 'width' }
};
else {
if (model.has(channel_1.Y)) {
p.y = {
scale: model.scaleName(channel_1.Y),
field: model.field(channel_1.Y, { binSuffix: '_mid' })
};
}
else {
p.y = { value: 0 };
}
if (model.has(channel_1.X)) {
p.x = {
scale: model.scaleName(channel_1.X),
field: model.field(channel_1.X, { binSuffix: '_mid' })
};
}
else {
p.x = { value: 0 };
}
if (model.has(channel_1.X2)) {
p.x2 = {
scale: model.scaleName(channel_1.X),
field: model.field(channel_1.X2, { binSuffix: '_mid' })
};
}
else {
p.x2 = { field: { group: 'width' } };
}
}

@@ -40,8 +84,2 @@ common_1.applyColorAndOpacity(p, model);

rule.properties = properties;
function position(model, channel) {
return {
scale: model.scaleName(channel),
field: model.field(channel, { binSuffix: '_mid' })
};
}
function sizeValue(model) {

@@ -48,0 +86,0 @@ var fieldDef = model.fieldDef(channel_1.SIZE);

@@ -1,2 +0,2 @@

import {X, Y, SIZE, Channel} from '../../channel';
import {X, Y, X2, Y2, SIZE} from '../../channel';

@@ -15,21 +15,56 @@ import {UnitModel} from '../unit';

// TODO: support explicit value
if(model.config().mark.orient === 'vertical') {
if (model.has(X)) {
p.x = {
scale: model.scaleName(X),
field: model.field(X, { binSuffix: '_mid' })
};
} else {
p.x = { value : 0 };
}
// vertical
if (model.has(X)) {
p.x = position(model, X);
if (model.has(Y)) {
p.y = {
scale: model.scaleName(Y),
field: model.field(Y, { binSuffix: '_mid' })
};
} else {
p.y = { field: { group: 'height' } };
}
p.y = { value: 0 };
p.y2 = {
field: {group: 'height'}
if (model.has(Y2)) {
p.y2 = {
scale: model.scaleName(Y),
field: model.field(Y2, { binSuffix: '_mid' })
};
}
} else {
p.y2 = { value: 0 };
}
} else {
if (model.has(Y)) {
p.y = {
scale: model.scaleName(Y),
field: model.field(Y, { binSuffix: '_mid' })
};
} else {
p.y = { value: 0 };
}
// horizontal
if (model.has(Y)) {
p.y = position(model, Y);
if (model.has(X)) {
p.x = {
scale: model.scaleName(X),
field: model.field(X, { binSuffix: '_mid' })
};
} else {
p.x = { value: 0 };
}
p.x = { value: 0 };
p.x2 = {
field: {group: 'width'}
if (model.has(X2)) {
p.x2 = {
scale: model.scaleName(X),
field: model.field(X2, { binSuffix: '_mid' })
};
} else {
p.x2 = { field: { group: 'width' } };
}
}

@@ -49,13 +84,5 @@

}
return p;
}
function position(model: UnitModel, channel: Channel) {
return {
scale: model.scaleName(channel),
field: model.field(channel, { binSuffix: '_mid' })
};
}
function sizeValue(model: UnitModel) {

@@ -62,0 +89,0 @@ const fieldDef = model.fieldDef(SIZE);

"use strict";
var channel_1 = require('../../channel');
var common_1 = require('../common');
var util_1 = require('../../util');
var fielddef_1 = require('../../fielddef');
var type_1 = require('../../type');
var text;
(function (text) {
(function (text_1) {
function markType() {
return 'text';
}
text.markType = markType;
text_1.markType = markType;
function background(model) {

@@ -24,3 +24,3 @@ return {

}
text.background = background;
text_1.background = background;
function properties(model) {

@@ -30,35 +30,8 @@ var p = {};

'fontStyle', 'radius', 'theta', 'text']);
var fieldDef = model.fieldDef(channel_1.TEXT);
if (model.has(channel_1.X)) {
p.x = {
scale: model.scaleName(channel_1.X),
field: model.field(channel_1.X, { binSuffix: '_mid' })
};
}
else {
if (model.has(channel_1.TEXT) && model.fieldDef(channel_1.TEXT).type === type_1.QUANTITATIVE) {
p.x = { field: { group: 'width' }, offset: -5 };
}
else {
p.x = { value: model.config().scale.textBandWidth / 2 };
}
}
if (model.has(channel_1.Y)) {
p.y = {
scale: model.scaleName(channel_1.Y),
field: model.field(channel_1.Y, { binSuffix: '_mid' })
};
}
else {
p.y = { value: model.config().scale.bandSize / 2 };
}
if (model.has(channel_1.SIZE)) {
p.fontSize = {
scale: model.scaleName(channel_1.SIZE),
field: model.field(channel_1.SIZE)
};
}
else {
p.fontSize = { value: sizeValue(model) };
}
var config = model.config();
var textFieldDef = model.fieldDef(channel_1.TEXT);
p.x = x(model.encoding().x, model.scaleName(channel_1.X), config, textFieldDef);
p.y = y(model.encoding().y, model.scaleName(channel_1.Y), config);
p.fontSize = size(model.encoding().size, model.scaleName(channel_1.SIZE), config);
p.text = text(model.encoding().text, model.scaleName(channel_1.TEXT), config);
if (model.config().mark.applyColorToBackground && !model.has(channel_1.X) && !model.has(channel_1.Y)) {

@@ -75,25 +48,72 @@ p.fill = { value: 'black' };

}
if (model.has(channel_1.TEXT)) {
if (util_1.contains([type_1.QUANTITATIVE, type_1.TEMPORAL], model.fieldDef(channel_1.TEXT).type)) {
var format = model.config().mark.format;
util_1.extend(p, common_1.formatMixins(model, channel_1.TEXT, format));
return p;
}
text_1.properties = properties;
function x(xFieldDef, scaleName, config, textFieldDef) {
if (xFieldDef) {
if (xFieldDef.field) {
return {
scale: scaleName,
field: fielddef_1.field(xFieldDef, { binSuffix: '_mid' })
};
}
else {
p.text = { field: model.field(channel_1.TEXT) };
}
if (textFieldDef && textFieldDef.type === type_1.QUANTITATIVE) {
return { field: { group: 'width' }, offset: -5 };
}
else {
return { value: config.scale.textBandWidth / 2 };
}
}
function y(yFieldDef, scaleName, config) {
if (yFieldDef) {
if (yFieldDef.field) {
return {
scale: scaleName,
field: fielddef_1.field(yFieldDef, { binSuffix: '_mid' })
};
}
}
else if (fieldDef.value) {
p.text = { value: fieldDef.value };
return { value: config.scale.bandSize / 2 };
}
function size(sizeFieldDef, scaleName, config) {
if (sizeFieldDef) {
if (sizeFieldDef.field) {
return {
scale: scaleName,
field: fielddef_1.field(sizeFieldDef)
};
}
if (sizeFieldDef.value) {
return { value: sizeFieldDef.value };
}
}
return p;
return { value: config.mark.fontSize };
}
text.properties = properties;
function sizeValue(model) {
var fieldDef = model.fieldDef(channel_1.SIZE);
if (fieldDef && fieldDef.value !== undefined) {
return fieldDef.value;
function text(textFieldDef, scaleName, config) {
if (textFieldDef) {
if (textFieldDef.field) {
if (type_1.QUANTITATIVE === textFieldDef.type) {
var format = common_1.numberFormat(textFieldDef, config.mark.format, config);
var filter = 'number' + (format ? ':\'' + format + '\'' : '');
return {
template: '{{' + fielddef_1.field(textFieldDef, { datum: true }) + ' | ' + filter + '}}'
};
}
else if (type_1.TEMPORAL === textFieldDef.type) {
return {
template: common_1.timeTemplate(fielddef_1.field(textFieldDef, { datum: true }), textFieldDef.timeUnit, config.mark.format, config.mark.shortTimeLabels, config)
};
}
else {
return { field: textFieldDef.field };
}
}
else if (textFieldDef.value) {
return { value: textFieldDef.value };
}
}
return model.config().mark.fontSize;
return { value: config.mark.text };
}
})(text = exports.text || (exports.text = {}));
//# sourceMappingURL=text.js.map

@@ -1,7 +0,11 @@

import {UnitModel} from '../unit';
import {X, Y, COLOR, TEXT, SIZE} from '../../channel';
import {applyMarkConfig, applyColorAndOpacity, formatMixins} from '../common';
import {extend, contains} from '../../util';
import {applyMarkConfig, applyColorAndOpacity, numberFormat, timeTemplate} from '../common';
import {Config} from '../../config';
import {FieldDef, field} from '../../fielddef';
import {QUANTITATIVE, ORDINAL, TEMPORAL} from '../../type';
import {VgValueRef} from '../../vega.schema';
import {UnitModel} from '../unit';
export namespace text {

@@ -33,41 +37,15 @@ export function markType() {

const fieldDef = model.fieldDef(TEXT);
const config = model.config();
const textFieldDef = model.fieldDef(TEXT);
// x
if (model.has(X)) {
p.x = {
scale: model.scaleName(X),
field: model.field(X, { binSuffix: '_mid' })
};
} else { // TODO: support x.value, x.datum
if (model.has(TEXT) && model.fieldDef(TEXT).type === QUANTITATIVE) {
p.x = { field: { group: 'width' }, offset: -5 };
} else {
p.x = { value: model.config().scale.textBandWidth / 2 };
}
}
p.x = x(model.encoding().x, model.scaleName(X), config, textFieldDef);
// y
if (model.has(Y)) {
p.y = {
scale: model.scaleName(Y),
field: model.field(Y, { binSuffix: '_mid' })
};
} else {
p.y = { value: model.config().scale.bandSize / 2 };
}
p.y = y(model.encoding().y, model.scaleName(Y), config);
// size
if (model.has(SIZE)) {
p.fontSize = {
scale: model.scaleName(SIZE),
field: model.field(SIZE)
};
} else {
p.fontSize = { value: sizeValue(model) };
}
p.fontSize = size(model.encoding().size, model.scaleName(SIZE), config);
p.text = text(model.encoding().text, model.scaleName(TEXT), config);
if (model.config().mark.applyColorToBackground && !model.has(X) && !model.has(Y)) {
p.fill = {value: 'black'}; // TODO: add rules for swapping between black and white
// opacity

@@ -80,26 +58,77 @@ const opacity = model.config().mark.opacity;

return p;
}
// text
if (model.has(TEXT)) {
if (contains([QUANTITATIVE, TEMPORAL], model.fieldDef(TEXT).type)) {
const format = model.config().mark.format;
extend(p, formatMixins(model, TEXT, format));
} else {
p.text = { field: model.field(TEXT) };
function x(xFieldDef: FieldDef, scaleName: string, config: Config, textFieldDef:FieldDef): VgValueRef {
// x
if (xFieldDef) {
if (xFieldDef.field) {
return {
scale: scaleName,
field: field(xFieldDef, { binSuffix: '_mid' })
};
}
} else if (fieldDef.value) {
p.text = { value: fieldDef.value };
}
// TODO: support x.value, x.datum
if (textFieldDef && textFieldDef.type === QUANTITATIVE) {
return { field: { group: 'width' }, offset: -5 };
} else {
return { value: config.scale.textBandWidth / 2 };
}
}
return p;
function y(yFieldDef: FieldDef, scaleName: string, config: Config): VgValueRef {
// y
if (yFieldDef) {
if (yFieldDef.field) {
return {
scale: scaleName,
field: field(yFieldDef, { binSuffix: '_mid' })
};
}
}
// TODO consider if this should support group: height case too.
return { value: config.scale.bandSize / 2 };
}
function sizeValue(model: UnitModel) {
const fieldDef = model.fieldDef(SIZE);
if (fieldDef && fieldDef.value !== undefined) {
return fieldDef.value;
function size(sizeFieldDef: FieldDef, scaleName: string, config: Config): VgValueRef {
// size
if (sizeFieldDef) {
if (sizeFieldDef.field) {
return {
scale: scaleName,
field: field(sizeFieldDef)
};
}
if (sizeFieldDef.value) {
return {value: sizeFieldDef.value};
}
}
return { value: config.mark.fontSize };
}
return model.config().mark.fontSize;
function text(textFieldDef: FieldDef, scaleName: string, config: Config): VgValueRef {
// text
if (textFieldDef) {
if (textFieldDef.field) {
if (QUANTITATIVE === textFieldDef.type) {
const format = numberFormat(textFieldDef, config.mark.format, config);
const filter = 'number' + ( format ? ':\'' + format + '\'' : '');
return {
template: '{{' + field(textFieldDef, { datum: true }) + ' | ' + filter + '}}'
};
} else if (TEMPORAL === textFieldDef.type) {
return {
template: timeTemplate(field(textFieldDef, {datum: true}), textFieldDef.timeUnit, config.mark.format, config.mark.shortTimeLabels, config)
};
} else {
return { field: textFieldDef.field };
}
} else if (textFieldDef.value) {
return { value: textFieldDef.value };
}
}
return {value: config.mark.text};
}
}
"use strict";
var aggregate_1 = require('../aggregate');
var channel_1 = require('../channel');
var config_1 = require('../config');
var data_1 = require('../data');

@@ -9,2 +8,3 @@ var fielddef_1 = require('../fielddef');

var scale_1 = require('../scale');
var stack_1 = require('../stack');
var timeunit_1 = require('../timeunit');

@@ -42,3 +42,21 @@ var type_1 = require('../type');

};
scaleDef.domain = domain(scale, model, channel);
if (channel === channel_1.X && model.has(channel_1.X2)) {
if (model.has(channel_1.X)) {
scaleDef.domain = { fields: [domain(scale, model, channel_1.X), domain(scale, model, channel_1.X2)] };
}
else {
scaleDef.domain = domain(scale, model, channel_1.X2);
}
}
else if (channel === channel_1.Y && model.has(channel_1.Y2)) {
if (model.has(channel_1.Y)) {
scaleDef.domain = { fields: [domain(scale, model, channel_1.Y), domain(scale, model, channel_1.Y2)] };
}
else {
scaleDef.domain = domain(scale, model, channel_1.Y2);
}
}
else {
scaleDef.domain = domain(scale, model, channel);
}
util_1.extend(scaleDef, rangeMixins(scale, model, channel));

@@ -119,2 +137,3 @@ if (sort && (typeof sort === 'string' ? sort : sort.order) === 'descending') {

case timeunit_1.TimeUnit.MONTH:
case timeunit_1.TimeUnit.QUARTER:
return scale_1.ScaleType.ORDINAL;

@@ -158,3 +177,3 @@ default:

if (stack && channel === stack.fieldChannel) {
if (stack.offset === config_1.StackOffset.NORMALIZE) {
if (stack.offset === stack_1.StackOffset.NORMALIZE) {
return [0, 1];

@@ -161,0 +180,0 @@ }

@@ -5,4 +5,3 @@ // https://github.com/Microsoft/TypeScript/blob/master/doc/spec.md#11-ambient-declarations

import {SHARED_DOMAIN_OPS} from '../aggregate';
import {COLUMN, ROW, X, Y, SHAPE, SIZE, COLOR, OPACITY, TEXT, hasScale, Channel} from '../channel';
import {StackOffset} from '../config';
import {COLUMN, ROW, X, Y, X2, Y2, SHAPE, SIZE, COLOR, OPACITY, TEXT, hasScale, Channel} from '../channel';
import {SOURCE, STACKED_SCALE} from '../data';

@@ -12,2 +11,3 @@ import {FieldDef, field, isMeasure} from '../fielddef';

import {Scale, ScaleType, NiceTime} from '../scale';
import {StackOffset} from '../stack';
import {TimeUnit} from '../timeunit';

@@ -45,2 +45,3 @@ import {NOMINAL, ORDINAL, QUANTITATIVE, TEMPORAL} from '../type';

export function parseScaleComponent(model: Model): Dict<ScaleComponents> {
// TODO: should model.channels() inlcude X2/Y2?
return model.channels().reduce(function(scale: Dict<ScaleComponents>, channel: Channel) {

@@ -74,3 +75,2 @@ if (model.scale(channel)) {

const sort = model.sort(channel);
let scaleDef: any = {

@@ -81,5 +81,20 @@ name: model.scaleName(channel),

scaleDef.domain = domain(scale, model, channel);
// If channel is either X or Y then union them with X2 & Y2 if they exist
if (channel === X && model.has(X2)) {
if (model.has(X)) {
scaleDef.domain = { fields: [domain(scale, model, X), domain(scale, model, X2)] };
} else {
scaleDef.domain = domain(scale, model, X2);
}
} else if (channel === Y && model.has(Y2)) {
if (model.has(Y)) {
scaleDef.domain = { fields: [domain(scale, model, Y), domain(scale, model, Y2)] };
} else {
scaleDef.domain = domain(scale, model, Y2);
}
} else {
scaleDef.domain = domain(scale, model, channel);
}
extend(scaleDef, rangeMixins(scale, model, channel));
if (sort && (typeof sort === 'string' ? sort : sort.order) === 'descending') {

@@ -185,2 +200,3 @@ scaleDef.reverse = true;

case TimeUnit.MONTH:
case TimeUnit.QUARTER:
return ScaleType.ORDINAL;

@@ -187,0 +203,0 @@ default:

@@ -9,18 +9,19 @@ "use strict";

}
if (timeUnit.indexOf('second') > -1) {
if (timeunit_1.containsTimeUnit(timeUnit, timeunit_1.TimeUnit.SECONDS)) {
return 'second';
}
if (timeUnit.indexOf('minute') > -1) {
if (timeunit_1.containsTimeUnit(timeUnit, timeunit_1.TimeUnit.MINUTES)) {
return 'minute';
}
if (timeUnit.indexOf('hour') > -1) {
if (timeunit_1.containsTimeUnit(timeUnit, timeunit_1.TimeUnit.HOURS)) {
return 'hour';
}
if (timeUnit.indexOf('day') > -1 || timeUnit.indexOf('date') > -1) {
if (timeunit_1.containsTimeUnit(timeUnit, timeunit_1.TimeUnit.DAY) ||
timeunit_1.containsTimeUnit(timeUnit, timeunit_1.TimeUnit.DATE)) {
return 'day';
}
if (timeUnit.indexOf('month') > -1) {
if (timeunit_1.containsTimeUnit(timeUnit, timeunit_1.TimeUnit.MONTH)) {
return 'month';
}
if (timeUnit.indexOf('year') > -1) {
if (timeunit_1.containsTimeUnit(timeUnit, timeunit_1.TimeUnit.YEAR)) {
return 'year';

@@ -34,4 +35,3 @@ }

var out = 'datetime(';
var timeString = timeUnit.toString();
function get(fun, addComma) {
function func(fun, addComma) {
if (addComma === void 0) { addComma = true; }

@@ -42,7 +42,14 @@ if (onlyRef) {

else {
return fun + '(' + fieldRef + ')' + (addComma ? ', ' : '');
var res = '';
if (fun === 'quarter') {
res = 'floor(month(' + fieldRef + ')' + '/3)*3';
}
else {
res = fun + '(' + fieldRef + ')';
}
return res + (addComma ? ', ' : '');
}
}
if (timeString.indexOf('year') > -1) {
out += get('year');
if (timeunit_1.containsTimeUnit(timeUnit, timeunit_1.TimeUnit.YEAR)) {
out += func('year');
}

@@ -52,13 +59,16 @@ else {

}
if (timeString.indexOf('month') > -1) {
out += get('month');
if (timeunit_1.containsTimeUnit(timeUnit, timeunit_1.TimeUnit.MONTH)) {
out += func('month');
}
else if (timeunit_1.containsTimeUnit(timeUnit, timeunit_1.TimeUnit.QUARTER)) {
out += func('quarter');
}
else {
out += '0, ';
}
if (timeString.indexOf('day') > -1) {
out += get('day', false) + '+1, ';
if (timeunit_1.containsTimeUnit(timeUnit, timeunit_1.TimeUnit.DAY)) {
out += func('day', false) + '+1, ';
}
else if (timeString.indexOf('date') > -1) {
out += get('date');
else if (timeunit_1.containsTimeUnit(timeUnit, timeunit_1.TimeUnit.DATE)) {
out += func('date');
}

@@ -68,4 +78,4 @@ else {

}
if (timeString.indexOf('hours') > -1) {
out += get('hours');
if (timeunit_1.containsTimeUnit(timeUnit, timeunit_1.TimeUnit.HOURS)) {
out += func('hours');
}

@@ -75,4 +85,4 @@ else {

}
if (timeString.indexOf('minutes') > -1) {
out += get('minutes');
if (timeunit_1.containsTimeUnit(timeUnit, timeunit_1.TimeUnit.MINUTES)) {
out += func('minutes');
}

@@ -82,4 +92,4 @@ else {

}
if (timeString.indexOf('seconds') > -1) {
out += get('seconds');
if (timeunit_1.containsTimeUnit(timeUnit, timeunit_1.TimeUnit.SECONDS)) {
out += func('seconds');
}

@@ -89,4 +99,4 @@ else {

}
if (timeString.indexOf('milliseconds') > -1) {
out += get('milliseconds', false);
if (timeunit_1.containsTimeUnit(timeUnit, timeunit_1.TimeUnit.MILLISECONDS)) {
out += func('milliseconds', false);
}

@@ -116,2 +126,4 @@ else {

return util_1.range(0, 12);
case timeunit_1.TimeUnit.QUARTER:
return [0, 3, 6, 9];
}

@@ -118,0 +130,0 @@ return null;

import {contains, range} from '../util';
import {COLUMN, ROW, SHAPE, COLOR, Channel} from '../channel';
import {TimeUnit} from '../timeunit';
import {TimeUnit, containsTimeUnit} from '../timeunit';

@@ -11,23 +11,24 @@ /** returns the smallest nice unit for scale.nice */

if (timeUnit.indexOf('second') > -1) {
if (containsTimeUnit(timeUnit, TimeUnit.SECONDS)) {
return 'second';
}
if (timeUnit.indexOf('minute') > -1) {
if (containsTimeUnit(timeUnit, TimeUnit.MINUTES)) {
return 'minute';
}
if (timeUnit.indexOf('hour') > -1) {
if (containsTimeUnit(timeUnit, TimeUnit.HOURS)) {
return 'hour';
}
if (timeUnit.indexOf('day') > -1 || timeUnit.indexOf('date') > -1) {
if (containsTimeUnit(timeUnit, TimeUnit.DAY) ||
containsTimeUnit(timeUnit, TimeUnit.DATE)) {
return 'day';
}
if (timeUnit.indexOf('month') > -1) {
if (containsTimeUnit(timeUnit, TimeUnit.MONTH)) {
return 'month';
}
if (timeUnit.indexOf('year') > -1) {
if (containsTimeUnit(timeUnit, TimeUnit.YEAR)) {
return 'year';

@@ -40,14 +41,21 @@ }

let out = 'datetime(';
let timeString = timeUnit.toString();
function get(fun: string, addComma = true) {
function func(fun: string, addComma = true) {
if (onlyRef) {
return fieldRef + (addComma ? ', ' : '');
} else {
return fun + '(' + fieldRef + ')' + (addComma ? ', ' : '');
let res = '';
if (fun === 'quarter') {
// Divide by 3 to get the corresponding quarter number, multiply by 3
// to scale to the first month of the corresponding quarter(0,3,6,9).
res = 'floor(month(' + fieldRef + ')' + '/3)*3';
} else {
res = fun + '(' + fieldRef + ')' ;
}
return res + (addComma ? ', ' : '');
}
}
if (timeString.indexOf('year') > -1) {
out += get('year');
if (containsTimeUnit(timeUnit, TimeUnit.YEAR)) {
out += func('year');
} else {

@@ -57,4 +65,6 @@ out += '2006, '; // January 1 2006 is a Sunday

if (timeString.indexOf('month') > -1) {
out += get('month');
if (containsTimeUnit(timeUnit, TimeUnit.MONTH)) {
out += func('month');
} else if (containsTimeUnit(timeUnit, TimeUnit.QUARTER)) {
out += func('quarter');
} else {

@@ -66,6 +76,6 @@ // month starts at 0 in javascript

// need to add 1 because days start at 1
if (timeString.indexOf('day') > -1) {
out += get('day', false) + '+1, ';
} else if (timeString.indexOf('date') > -1) {
out += get('date');
if (containsTimeUnit(timeUnit, TimeUnit.DAY)) {
out += func('day', false) + '+1, ';
} else if (containsTimeUnit(timeUnit, TimeUnit.DATE)) {
out += func('date');
} else {

@@ -75,4 +85,4 @@ out += '1, ';

if (timeString.indexOf('hours') > -1) {
out += get('hours');
if (containsTimeUnit(timeUnit, TimeUnit.HOURS)) {
out += func('hours');
} else {

@@ -82,4 +92,4 @@ out += '0, ';

if (timeString.indexOf('minutes') > -1) {
out += get('minutes');
if (containsTimeUnit(timeUnit, TimeUnit.MINUTES)) {
out += func('minutes');
} else {

@@ -89,4 +99,4 @@ out += '0, ';

if (timeString.indexOf('seconds') > -1) {
out += get('seconds');
if (containsTimeUnit(timeUnit, TimeUnit.SECONDS)) {
out += func('seconds');
} else {

@@ -96,4 +106,4 @@ out += '0, ';

if (timeString.indexOf('milliseconds') > -1) {
out += get('milliseconds', false);
if (containsTimeUnit(timeUnit, TimeUnit.MILLISECONDS)) {
out += func('milliseconds', false);
} else {

@@ -125,2 +135,4 @@ out += '0';

return range(0, 12);
case TimeUnit.QUARTER:
return [0,3,6,9];
}

@@ -127,0 +139,0 @@

@@ -26,3 +26,3 @@ "use strict";

var scale_2 = require('./scale');
var stack_1 = require('./stack');
var stack_1 = require('../stack');
var UnitModel = (function (_super) {

@@ -35,6 +35,6 @@ __extends(UnitModel, _super);

var config = this._config = this._initConfig(spec.config, parent, mark, encoding);
var scale = this._scale = this._initScale(mark, encoding, config);
this._scale = this._initScale(mark, encoding, config);
this._axis = this._initAxis(encoding, config);
this._legend = this._initLegend(encoding, config);
this._stack = stack_1.compileStackProperties(mark, encoding, scale, config);
this._stack = stack_1.stack(mark, encoding, config);
}

@@ -65,5 +65,7 @@ UnitModel.prototype._initEncoding = function (mark, encoding) {

return channel_1.UNIT_SCALE_CHANNELS.reduce(function (_scale, channel) {
if (vlEncoding.has(encoding, channel)) {
var scaleSpec = encoding[channel].scale || {};
if (vlEncoding.has(encoding, channel) ||
(channel === channel_1.X && vlEncoding.has(encoding, channel_1.X2)) ||
(channel === channel_1.Y && vlEncoding.has(encoding, channel_1.Y2))) {
var channelDef = encoding[channel];
var scaleSpec = (channelDef || {}).scale || {};
var _scaleType = scale_2.scaleType(scaleSpec, channelDef, channel, mark);

@@ -84,4 +86,6 @@ _scale[channel] = util_1.extend({

return [channel_1.X, channel_1.Y].reduce(function (_axis, channel) {
if (vlEncoding.has(encoding, channel)) {
var axisSpec = encoding[channel].axis;
if (vlEncoding.has(encoding, channel) ||
(channel === channel_1.X && vlEncoding.has(encoding, channel_1.X2)) ||
(channel === channel_1.Y && vlEncoding.has(encoding, channel_1.Y2))) {
var axisSpec = (encoding[channel] || {}).axis;
if (axisSpec !== false) {

@@ -88,0 +92,0 @@ _axis[channel] = util_1.extend({}, config.axis, axisSpec === true ? {} : axisSpec || {});

import {AggregateOp} from '../aggregate';
import {Axis} from '../axis';
import {X, Y, TEXT, PATH, ORDER, Channel, UNIT_CHANNELS, UNIT_SCALE_CHANNELS, NONSPATIAL_SCALE_CHANNELS, supportMark} from '../channel';
import {X, Y, X2, Y2, TEXT, PATH, ORDER, Channel, UNIT_CHANNELS, UNIT_SCALE_CHANNELS, NONSPATIAL_SCALE_CHANNELS, supportMark} from '../channel';
import {defaultConfig, Config, CellConfig} from '../config';

@@ -26,3 +26,3 @@ import {SOURCE, SUMMARY} from '../data';

import {parseScaleComponent, scaleType} from './scale';
import {compileStackProperties, StackProperties} from './stack';
import {stack, StackProperties} from '../stack';

@@ -45,8 +45,8 @@ /**

const scale = this._scale = this._initScale(mark, encoding, config);
this._scale = this._initScale(mark, encoding, config);
this._axis = this._initAxis(encoding, config);
this._legend = this._initLegend(encoding, config);
// calculate stack
this._stack = compileStackProperties(mark, encoding, scale, config);
// calculate stack properties
this._stack = stack(mark, encoding, config);
}

@@ -88,6 +88,9 @@

return UNIT_SCALE_CHANNELS.reduce(function(_scale, channel) {
if (vlEncoding.has(encoding, channel)) {
const scaleSpec = encoding[channel].scale || {};
if (vlEncoding.has(encoding, channel) ||
(channel === X && vlEncoding.has(encoding, X2)) ||
(channel === Y && vlEncoding.has(encoding, Y2))
) {
const channelDef = encoding[channel];
const scaleSpec = (channelDef || {}).scale || {};
const _scaleType = scaleType(scaleSpec, channelDef, channel, mark);

@@ -111,4 +114,7 @@

// Position Axis
if (vlEncoding.has(encoding, channel)) {
const axisSpec = encoding[channel].axis;
if (vlEncoding.has(encoding, channel) ||
(channel === X && vlEncoding.has(encoding, X2)) ||
(channel === Y && vlEncoding.has(encoding, Y2))) {
const axisSpec = (encoding[channel] || {}).axis;
if (axisSpec !== false) {

@@ -115,0 +121,0 @@ _axis[channel] = extend({},

@@ -55,9 +55,2 @@ "use strict";

var FontStyle = exports.FontStyle;
(function (StackOffset) {
StackOffset[StackOffset["ZERO"] = 'zero'] = "ZERO";
StackOffset[StackOffset["CENTER"] = 'center'] = "CENTER";
StackOffset[StackOffset["NORMALIZE"] = 'normalize'] = "NORMALIZE";
StackOffset[StackOffset["NONE"] = 'none'] = "NONE";
})(exports.StackOffset || (exports.StackOffset = {}));
var StackOffset = exports.StackOffset;
(function (Interpolate) {

@@ -79,2 +72,13 @@ Interpolate[Interpolate["LINEAR"] = 'linear'] = "LINEAR";

var Interpolate = exports.Interpolate;
(function (AreaOverlay) {
AreaOverlay[AreaOverlay["LINE"] = 'line'] = "LINE";
AreaOverlay[AreaOverlay["LINEPOINT"] = 'linepoint'] = "LINEPOINT";
AreaOverlay[AreaOverlay["NONE"] = 'none'] = "NONE";
})(exports.AreaOverlay || (exports.AreaOverlay = {}));
var AreaOverlay = exports.AreaOverlay;
exports.defaultOverlayConfig = {
line: false,
pointStyle: { filled: true },
lineStyle: {}
};
exports.defaultMarkConfig = {

@@ -99,2 +103,3 @@ color: '#4682b4',

mark: exports.defaultMarkConfig,
overlay: exports.defaultOverlayConfig,
scale: scale_1.defaultScaleConfig,

@@ -101,0 +106,0 @@ axis: axis_1.defaultAxisConfig,

import {ScaleConfig, FacetScaleConfig, defaultScaleConfig, defaultFacetScaleConfig} from './scale';
import {AxisConfig, defaultAxisConfig, defaultFacetAxisConfig} from './axis';
import {LegendConfig, defaultLegendConfig} from './legend';
import {StackOffset} from './stack';

@@ -112,9 +113,4 @@ export interface CellConfig {

export enum StackOffset {
ZERO = 'zero' as any,
CENTER = 'center' as any,
NORMALIZE = 'normalize' as any,
NONE = 'none' as any,
}
export enum Interpolate {

@@ -149,2 +145,36 @@ /** piecewise linear segments, as in a polyline */

export enum AreaOverlay {
LINE = 'line' as any,
LINEPOINT = 'linepoint' as any,
NONE = 'none' as any
}
export interface OverlayConfig {
/**
* Whether to overlay line with point.
*/
line?: boolean;
/**
* Type of overlay for area mark (line or linepoint)
*/
area?: AreaOverlay;
/**
* Default style for the overlayed point.
*/
pointStyle?: MarkConfig;
/**
* Default style for the overlayed point.
*/
lineStyle?: MarkConfig;
}
export const defaultOverlayConfig: OverlayConfig = {
line: false,
pointStyle: {filled: true},
lineStyle: {}
};
export interface MarkConfig {

@@ -399,2 +429,5 @@

/** Mark Overlay Config */
overlay?: OverlayConfig;
/** Scale Config */

@@ -419,2 +452,3 @@ scale?: ScaleConfig;

mark: defaultMarkConfig,
overlay: defaultOverlayConfig,
scale: defaultScaleConfig,

@@ -421,0 +455,0 @@ axis: defaultAxisConfig,

"use strict";
var type_1 = require('./type');
(function (DataFormat) {
DataFormat[DataFormat["JSON"] = 'json'] = "JSON";
DataFormat[DataFormat["CSV"] = 'csv'] = "CSV";
DataFormat[DataFormat["TSV"] = 'tsv'] = "TSV";
})(exports.DataFormat || (exports.DataFormat = {}));
var DataFormat = exports.DataFormat;
(function (DataFormatType) {
DataFormatType[DataFormatType["JSON"] = 'json'] = "JSON";
DataFormatType[DataFormatType["CSV"] = 'csv'] = "CSV";
DataFormatType[DataFormatType["TSV"] = 'tsv'] = "TSV";
DataFormatType[DataFormatType["TOPOJSON"] = 'topojson'] = "TOPOJSON";
})(exports.DataFormatType || (exports.DataFormatType = {}));
var DataFormatType = exports.DataFormatType;
(function (DataTable) {

@@ -10,0 +11,0 @@ DataTable[DataTable["SOURCE"] = 'source'] = "SOURCE";

@@ -6,12 +6,46 @@ /*

export enum DataFormat {
export interface DataFormat {
/**
* Type of input data: `"json"`, `"csv"`, `"tsv"`.
* The default format type is determined by the extension of the file url.
* If no extension is detected, `"json"` will be used by default.
*/
type?: DataFormatType;
/**
* JSON only) The JSON property containing the desired data.
* This parameter can be used when the loaded JSON file may have surrounding structure or meta-data.
* For example `"property": "values.features"` is equivalent to retrieving `json.values.features`
* from the loaded JSON object.
*/
property?: string;
/**
* The name of the TopoJSON object set to convert to a GeoJSON feature collection.
* For example, in a map of the world, there may be an object set named `"countries"`.
* Using the feature property, we can extract this set and generate a GeoJSON feature object for each country.
*/
feature?: string;
/**
* The name of the TopoJSON object set to convert to a mesh.
* Similar to the `feature` option, `mesh` extracts a named TopoJSON object set.
* Unlike the `feature` option, the corresponding geo data is returned as a single, unified mesh instance, not as inidividual GeoJSON features.
* Extracting a mesh is useful for more efficiently drawing borders or other geographic elements that you do not need to associate with specific regions such as individual countries, states or counties.
*/
mesh?: string;
}
export enum DataFormatType {
JSON = 'json' as any,
CSV = 'csv' as any,
TSV = 'tsv' as any,
TOPOJSON = 'topojson' as any
}
export interface Data {
formatType?: DataFormat;
/**
* An object that specifies the format for the data file or values.
*/
format?: DataFormat;
/**

@@ -18,0 +52,0 @@ * A URL from which to load the data set. Use the formatType property

@@ -34,3 +34,3 @@ "use strict";

function isAggregate(encoding) {
return util_1.any(channel_1.CHANNELS, function (channel) {
return util_1.some(channel_1.CHANNELS, function (channel) {
if (has(encoding, channel) && encoding[channel].aggregate) {

@@ -43,2 +43,6 @@ return true;

exports.isAggregate = isAggregate;
function isRanged(encoding) {
return encoding && ((!!encoding.x && !!encoding.x2) || (!!encoding.y && !!encoding.y2));
}
exports.isRanged = isRanged;
function fieldDefs(encoding) {

@@ -45,0 +49,0 @@ var arr = [];

// utility for encoding mapping
import {FieldDef, PositionChannelDef, FacetChannelDef, ChannelDefWithLegend, OrderChannelDef} from './fielddef';
import {Channel, CHANNELS} from './channel';
import {isArray, any as anyIn} from './util';
import {isArray, some} from './util';

@@ -23,2 +23,12 @@ // TODO: once we decompose facet, rename this to Encoding

/**
* X2 coordinates for ranged `bar`, `rule`, `area`
*/
x2?: PositionChannelDef;
/**
* Y2 coordinates for ranged `bar`, `rule`, `area`
*/
y2?: PositionChannelDef;
/**
* Color of the marks – either fill or stroke color based on mark type.

@@ -103,2 +113,3 @@ * (By default, fill color for `area`, `bar`, `tick`, `text`, `circle`, and `square` /

// TOD: rename this to hasChannelField and only use we really want it.
export function has(encoding: Encoding, channel: Channel): boolean {

@@ -108,2 +119,3 @@ const channelEncoding = encoding && encoding[channel];

channelEncoding.field !== undefined ||
// TODO: check that we have field in the array
(isArray(channelEncoding) && channelEncoding.length > 0)

@@ -114,3 +126,3 @@ );

export function isAggregate(encoding: Encoding) {
return anyIn(CHANNELS, (channel) => {
return some(CHANNELS, (channel) => {
if (has(encoding, channel) && encoding[channel].aggregate) {

@@ -123,2 +135,6 @@ return true;

export function isRanged(encoding: Encoding) {
return encoding && ((!!encoding.x && !!encoding.x2) || (!!encoding.y && !!encoding.y2));
}
export function fieldDefs(encoding: Encoding): FieldDef[] {

@@ -125,0 +141,0 @@ let arr = [];

@@ -89,2 +89,3 @@ "use strict";

case timeunit_1.TimeUnit.MONTH: return 12;
case timeunit_1.TimeUnit.QUARTER: return 4;
case timeunit_1.TimeUnit.YEAR:

@@ -91,0 +92,0 @@ var yearstat = stats['year_' + fieldDef.field];

@@ -196,2 +196,3 @@ // utility for a field definition object

case TimeUnit.MONTH: return 12;
case TimeUnit.QUARTER: return 4;
case TimeUnit.YEAR:

@@ -198,0 +199,0 @@ const yearstat = stats['year_' + fieldDef.field];

@@ -12,2 +12,3 @@ "use strict";

Mark[Mark["SQUARE"] = 'square'] = "SQUARE";
Mark[Mark["ERRORBAR"] = 'errorBar'] = "ERRORBAR";
})(exports.Mark || (exports.Mark = {}));

@@ -24,2 +25,4 @@ var Mark = exports.Mark;

exports.SQUARE = Mark.SQUARE;
exports.ERRORBAR = Mark.ERRORBAR;
exports.PRIMITIVE_MARKS = [exports.AREA, exports.BAR, exports.LINE, exports.POINT, exports.TEXT, exports.TICK, exports.RULE, exports.CIRCLE, exports.SQUARE];
//# sourceMappingURL=mark.js.map

@@ -10,3 +10,4 @@ export enum Mark {

CIRCLE = 'circle' as any,
SQUARE = 'square' as any
SQUARE = 'square' as any,
ERRORBAR = 'errorBar' as any
}

@@ -24,1 +25,4 @@

export const SQUARE = Mark.SQUARE;
export const ERRORBAR = Mark.ERRORBAR;
export const PRIMITIVE_MARKS = [AREA, BAR, LINE, POINT, TEXT, TICK, RULE, CIRCLE, SQUARE];
"use strict";
var config_1 = require('./config');
var encoding_1 = require('./encoding');
var mark_1 = require('./mark');
var stack_1 = require('./stack');
var channel_1 = require('./channel');
var vlEncoding = require('./encoding');
var mark_1 = require('./mark');
var util_1 = require('./util');

@@ -37,18 +39,125 @@ function isFacetSpec(spec) {

if (isExtendedUnitSpec(spec)) {
var hasRow = encoding_1.has(spec.encoding, channel_1.ROW);
var hasColumn = encoding_1.has(spec.encoding, channel_1.COLUMN);
var encoding = util_1.duplicate(spec.encoding);
delete encoding.column;
delete encoding.row;
return util_1.extend(spec.name ? { name: spec.name } : {}, spec.description ? { description: spec.description } : {}, { data: spec.data }, spec.transform ? { transform: spec.transform } : {}, {
facet: util_1.extend(hasRow ? { row: spec.encoding.row } : {}, hasColumn ? { column: spec.encoding.column } : {}),
spec: {
mark: spec.mark,
encoding: encoding
return normalizeExtendedUnitSpec(spec);
}
if (isUnitSpec(spec)) {
return normalizeUnitSpec(spec);
}
return spec;
}
exports.normalize = normalize;
function normalizeExtendedUnitSpec(spec) {
var hasRow = encoding_1.has(spec.encoding, channel_1.ROW);
var hasColumn = encoding_1.has(spec.encoding, channel_1.COLUMN);
var encoding = util_1.duplicate(spec.encoding);
delete encoding.column;
delete encoding.row;
return util_1.extend(spec.name ? { name: spec.name } : {}, spec.description ? { description: spec.description } : {}, { data: spec.data }, spec.transform ? { transform: spec.transform } : {}, {
facet: util_1.extend(hasRow ? { row: spec.encoding.row } : {}, hasColumn ? { column: spec.encoding.column } : {}),
spec: normalizeUnitSpec({
mark: spec.mark,
encoding: encoding
})
}, spec.config ? { config: spec.config } : {});
}
exports.normalizeExtendedUnitSpec = normalizeExtendedUnitSpec;
function normalizeUnitSpec(spec) {
var config = spec.config;
var overlayConfig = config && config.overlay;
var overlayWithLine = overlayConfig && spec.mark === mark_1.AREA &&
util_1.contains([config_1.AreaOverlay.LINEPOINT, config_1.AreaOverlay.LINE], overlayConfig.area);
var overlayWithPoint = overlayConfig && ((overlayConfig.line && spec.mark === mark_1.LINE) ||
(overlayConfig.area === config_1.AreaOverlay.LINEPOINT && spec.mark === mark_1.AREA));
if (spec.mark === mark_1.ERRORBAR) {
return normalizeErrorBarUnitSpec(spec);
}
if (encoding_1.isRanged(spec.encoding)) {
return normalizeRangedUnitSpec(spec);
}
if (isStacked(spec)) {
return spec;
}
if (overlayWithPoint || overlayWithLine) {
return normalizeOverlay(spec, overlayWithPoint, overlayWithLine);
}
return spec;
}
exports.normalizeUnitSpec = normalizeUnitSpec;
function normalizeRangedUnitSpec(spec) {
if (spec.encoding) {
var hasX = encoding_1.has(spec.encoding, channel_1.X);
var hasY = encoding_1.has(spec.encoding, channel_1.Y);
var hasX2 = encoding_1.has(spec.encoding, channel_1.X2);
var hasY2 = encoding_1.has(spec.encoding, channel_1.Y2);
if ((hasX2 && !hasX) || (hasY2 && !hasY)) {
var normalizedSpec = util_1.duplicate(spec);
if (hasX2 && !hasX) {
normalizedSpec.encoding.x = normalizedSpec.encoding.x2;
delete normalizedSpec.encoding.x2;
}
}, spec.config ? { config: spec.config } : {});
if (hasY2 && !hasY) {
normalizedSpec.encoding.y = normalizedSpec.encoding.y2;
delete normalizedSpec.encoding.y2;
}
return normalizedSpec;
}
}
return spec;
}
exports.normalize = normalize;
exports.normalizeRangedUnitSpec = normalizeRangedUnitSpec;
function normalizeErrorBarUnitSpec(spec) {
var layerSpec = util_1.extend(spec.name ? { name: spec.name } : {}, spec.description ? { description: spec.description } : {}, spec.data ? { data: spec.data } : {}, spec.transform ? { transform: spec.transform } : {}, spec.config ? { config: spec.config } : {}, { layers: [] });
if (!spec.encoding) {
return layerSpec;
}
if (spec.mark === mark_1.ERRORBAR) {
var ruleSpec = {
mark: mark_1.RULE,
encoding: util_1.extend(spec.encoding.x ? { x: util_1.duplicate(spec.encoding.x) } : {}, spec.encoding.y ? { y: util_1.duplicate(spec.encoding.y) } : {}, spec.encoding.x2 ? { x2: util_1.duplicate(spec.encoding.x2) } : {}, spec.encoding.y2 ? { y2: util_1.duplicate(spec.encoding.y2) } : {}, {})
};
var lowerTickSpec = {
mark: mark_1.TICK,
encoding: util_1.extend(spec.encoding.x ? { x: util_1.duplicate(spec.encoding.x) } : {}, spec.encoding.y ? { y: util_1.duplicate(spec.encoding.y) } : {}, spec.encoding.size ? { size: util_1.duplicate(spec.encoding.size) } : {}, {})
};
var upperTickSpec = {
mark: mark_1.TICK,
encoding: util_1.extend({
x: spec.encoding.x2 ? util_1.duplicate(spec.encoding.x2) : util_1.duplicate(spec.encoding.x),
y: spec.encoding.y2 ? util_1.duplicate(spec.encoding.y2) : util_1.duplicate(spec.encoding.y)
}, spec.encoding.size ? { size: util_1.duplicate(spec.encoding.size) } : {})
};
layerSpec.layers.push(normalizeUnitSpec(ruleSpec));
layerSpec.layers.push(normalizeUnitSpec(lowerTickSpec));
layerSpec.layers.push(normalizeUnitSpec(upperTickSpec));
}
return layerSpec;
}
exports.normalizeErrorBarUnitSpec = normalizeErrorBarUnitSpec;
function normalizeOverlay(spec, overlayWithPoint, overlayWithLine) {
var outerProps = ['name', 'description', 'data', 'transform'];
var baseSpec = util_1.omit(spec, outerProps.concat('config'));
var baseConfig = util_1.duplicate(spec.config);
delete baseConfig.overlay;
var layerSpec = util_1.extend(util_1.pick(spec, outerProps), { layers: [baseSpec] }, util_1.keys(baseConfig).length > 0 ? { config: baseConfig } : {});
if (overlayWithLine) {
var lineSpec = util_1.duplicate(baseSpec);
lineSpec.mark = mark_1.LINE;
var markConfig = util_1.extend({}, config_1.defaultOverlayConfig.lineStyle, spec.config.overlay.lineStyle);
if (util_1.keys(markConfig).length > 0) {
lineSpec.config = { mark: markConfig };
}
layerSpec.layers.push(lineSpec);
}
if (overlayWithPoint) {
var pointSpec = util_1.duplicate(baseSpec);
pointSpec.mark = mark_1.POINT;
var markConfig = util_1.extend({}, config_1.defaultOverlayConfig.pointStyle, spec.config.overlay.pointStyle);
;
if (util_1.keys(markConfig).length > 0) {
pointSpec.config = { mark: markConfig };
}
layerSpec.layers.push(pointSpec);
}
return layerSpec;
}
exports.normalizeOverlay = normalizeOverlay;
function alwaysNoOcclusion(spec) {

@@ -67,9 +176,6 @@ return vlEncoding.isAggregate(spec.encoding);

exports.getCleanSpec = getCleanSpec;
function isStack(spec) {
return (vlEncoding.has(spec.encoding, channel_1.COLOR) || vlEncoding.has(spec.encoding, channel_1.SHAPE)) &&
(spec.mark === mark_1.BAR || spec.mark === mark_1.AREA) &&
(!spec.config || !spec.config.mark.stacked !== false) &&
vlEncoding.isAggregate(spec.encoding);
function isStacked(spec) {
return stack_1.stack(spec.mark, spec.encoding, spec.config) !== null;
}
exports.isStack = isStack;
exports.isStacked = isStacked;
function transpose(spec) {

@@ -76,0 +182,0 @@ var oldenc = spec.encoding;

@@ -1,17 +0,14 @@

/* Utilities for a Vega-Lite specificiation */
/* Package of defining Vega-lite Specification's json schema at its utility functions */
import {FieldDef} from './fielddef';
// Package of defining Vega-lite Specification's json schema
import {Config} from './config';
import {Config, defaultOverlayConfig, AreaOverlay} from './config';
import {Data} from './data';
import {Encoding, UnitEncoding, has} from './encoding';
import {Encoding, UnitEncoding, has, isRanged} from './encoding';
import {Facet} from './facet';
import {Mark} from './mark';
import {FieldDef} from './fielddef';
import {Mark, ERRORBAR, TICK, AREA, RULE, LINE, POINT} from './mark';
import {stack} from './stack';
import {Transform} from './transform';
import {COLOR, SHAPE, ROW, COLUMN} from './channel';
import {ROW, COLUMN, X, Y, X2, Y2} from './channel';
import * as vlEncoding from './encoding';
import {BAR, AREA} from './mark';
import {duplicate, extend} from './util';
import {contains, duplicate, extend, keys, omit, pick} from './util';

@@ -138,7 +135,18 @@ export interface BaseSpec {

/**
* Decompose extended unit specs into composition of pure unit specs.
*/
// TODO: consider moving this to another file. Maybe vl.spec.normalize or vl.normalize
export function normalize(spec: ExtendedSpec): Spec {
if (isExtendedUnitSpec(spec)) {
return normalizeExtendedUnitSpec(spec);
}
if (isUnitSpec(spec)) {
return normalizeUnitSpec(spec);
}
return spec;
}
export function normalizeExtendedUnitSpec(spec: ExtendedUnitSpec): Spec {
const hasRow = has(spec.encoding, ROW);

@@ -162,14 +170,148 @@ const hasColumn = has(spec.encoding, COLUMN);

),
spec: {
spec: normalizeUnitSpec({
mark: spec.mark,
encoding: encoding
}
})
},
spec.config ? { config: spec.config } : {}
);
}
export function normalizeUnitSpec(spec: UnitSpec): Spec {
const config = spec.config;
const overlayConfig = config && config.overlay;
const overlayWithLine = overlayConfig && spec.mark === AREA &&
contains([AreaOverlay.LINEPOINT, AreaOverlay.LINE], overlayConfig.area);
const overlayWithPoint = overlayConfig && (
(overlayConfig.line && spec.mark === LINE) ||
(overlayConfig.area === AreaOverlay.LINEPOINT && spec.mark === AREA)
);
// TODO: thoroughly test
if (spec.mark === ERRORBAR) {
return normalizeErrorBarUnitSpec(spec);
}
// TODO: thoroughly test
if (isRanged(spec.encoding)) {
return normalizeRangedUnitSpec(spec);
}
if (isStacked(spec)) {
// We can't overlay stacked area yet!
return spec;
}
if (overlayWithPoint || overlayWithLine) {
return normalizeOverlay(spec, overlayWithPoint, overlayWithLine);
}
return spec;
}
export function normalizeRangedUnitSpec(spec: UnitSpec): Spec {
if (spec.encoding) {
const hasX = has(spec.encoding, X);
const hasY = has(spec.encoding, Y);
const hasX2 = has(spec.encoding, X2);
const hasY2 = has(spec.encoding, Y2);
if ((hasX2 && !hasX) || (hasY2 && !hasY)) {
let normalizedSpec = duplicate(spec);
if (hasX2 && !hasX) {
normalizedSpec.encoding.x = normalizedSpec.encoding.x2;
delete normalizedSpec.encoding.x2;
}
if (hasY2 && !hasY) {
normalizedSpec.encoding.y = normalizedSpec.encoding.y2;
delete normalizedSpec.encoding.y2;
}
return normalizedSpec;
}
}
return spec;
}
export function normalizeErrorBarUnitSpec(spec: UnitSpec): Spec {
// FIXME correctly deal with color and opacity
let layerSpec = extend(spec.name ? {name: spec.name} : {},
spec.description ? {description: spec.description} : {},
spec.data ? {data: spec.data} : {},
spec.transform ? {transform: spec.transform} : {},
spec.config ? {config: spec.config} : {}, {layers: []}
);
if (!spec.encoding) {
return layerSpec;
}
if (spec.mark === ERRORBAR) {
const ruleSpec = {
mark: RULE,
encoding: extend(
spec.encoding.x ? {x: duplicate(spec.encoding.x)} : {},
spec.encoding.y ? {y: duplicate(spec.encoding.y)} : {},
spec.encoding.x2 ? {x2: duplicate(spec.encoding.x2)} : {},
spec.encoding.y2 ? {y2: duplicate(spec.encoding.y2)} : {},
{})
};
const lowerTickSpec = {
mark: TICK,
encoding: extend(
spec.encoding.x ? {x: duplicate(spec.encoding.x)} : {},
spec.encoding.y ? {y: duplicate(spec.encoding.y)} : {},
spec.encoding.size ? {size: duplicate(spec.encoding.size)} : {},
{})
};
const upperTickSpec = {
mark: TICK,
encoding: extend({
x: spec.encoding.x2 ? duplicate(spec.encoding.x2) : duplicate(spec.encoding.x),
y: spec.encoding.y2 ? duplicate(spec.encoding.y2) : duplicate(spec.encoding.y)
}, spec.encoding.size ? {size: duplicate(spec.encoding.size)} : {})
};
layerSpec.layers.push(normalizeUnitSpec(ruleSpec));
layerSpec.layers.push(normalizeUnitSpec(lowerTickSpec));
layerSpec.layers.push(normalizeUnitSpec(upperTickSpec));
}
return layerSpec;
}
export function normalizeOverlay(spec: UnitSpec, overlayWithPoint: boolean, overlayWithLine: boolean): LayerSpec {
let outerProps = ['name', 'description', 'data', 'transform'];
let baseSpec = omit(spec, outerProps.concat('config'));
let baseConfig = duplicate(spec.config);
delete baseConfig.overlay;
// TODO: remove shape, size
const layerSpec = extend(
pick(spec, outerProps),
{ layers: [baseSpec] },
keys(baseConfig).length > 0 ? { config: baseConfig } : {}
);
if (overlayWithLine) {
// TODO: add name with suffix
let lineSpec = duplicate(baseSpec);
lineSpec.mark = LINE;
// TODO: remove shape, size
let markConfig = extend({}, defaultOverlayConfig.lineStyle, spec.config.overlay.lineStyle);
if (keys(markConfig).length > 0) {
lineSpec.config = {mark: markConfig};
}
layerSpec.layers.push(lineSpec);
}
if (overlayWithPoint) {
// TODO: add name with suffix
let pointSpec = duplicate(baseSpec);
pointSpec.mark = POINT;
let markConfig = extend({}, defaultOverlayConfig.pointStyle, spec.config.overlay.pointStyle);;
if (keys(markConfig).length > 0) {
pointSpec.config = {mark: markConfig};
}
layerSpec.layers.push(pointSpec);
}
return layerSpec;
}
// TODO: add vl.spec.validate & move stuff from vl.validate to here

@@ -192,7 +334,4 @@

export function isStack(spec: ExtendedUnitSpec): boolean {
return (vlEncoding.has(spec.encoding, COLOR) || vlEncoding.has(spec.encoding, SHAPE)) &&
(spec.mark === BAR || spec.mark === AREA) &&
(!spec.config || !spec.config.mark.stacked !== false) &&
vlEncoding.isAggregate(spec.encoding);
export function isStacked(spec: ExtendedUnitSpec): boolean {
return stack(spec.mark, spec.encoding, spec.config) !== null;
}

@@ -199,0 +338,0 @@

@@ -23,2 +23,6 @@ "use strict";

TimeUnit[TimeUnit["SECONDSMILLISECONDS"] = 'secondsmilliseconds'] = "SECONDSMILLISECONDS";
TimeUnit[TimeUnit["QUARTER"] = 'quarter'] = "QUARTER";
TimeUnit[TimeUnit["YEARQUARTER"] = 'yearquarter'] = "YEARQUARTER";
TimeUnit[TimeUnit["QUARTERMONTH"] = 'quartermonth'] = "QUARTERMONTH";
TimeUnit[TimeUnit["YEARQUARTERMONTH"] = 'yearquartermonth'] = "YEARQUARTERMONTH";
})(exports.TimeUnit || (exports.TimeUnit = {}));

@@ -47,33 +51,38 @@ var TimeUnit = exports.TimeUnit;

TimeUnit.SECONDSMILLISECONDS,
TimeUnit.QUARTER,
TimeUnit.YEARQUARTER,
TimeUnit.QUARTERMONTH,
TimeUnit.YEARQUARTERMONTH,
];
function format(timeUnit, abbreviated) {
if (abbreviated === void 0) { abbreviated = false; }
function template(timeUnit, field, shortTimeLabels) {
if (!timeUnit) {
return undefined;
}
var timeString = timeUnit.toString();
var dateComponents = [];
if (timeString.indexOf('year') > -1) {
dateComponents.push(abbreviated ? '%y' : '%Y');
if (containsTimeUnit(timeUnit, TimeUnit.YEAR)) {
dateComponents.push(shortTimeLabels ? '%y' : '%Y');
}
if (timeString.indexOf('month') > -1) {
dateComponents.push(abbreviated ? '%b' : '%B');
if (containsTimeUnit(timeUnit, TimeUnit.QUARTER)) {
dateComponents.push('\'}}Q{{' + field + ' | quarter}}{{' + field + ' | time:\'');
}
if (timeString.indexOf('day') > -1) {
dateComponents.push(abbreviated ? '%a' : '%A');
if (containsTimeUnit(timeUnit, TimeUnit.MONTH)) {
dateComponents.push(shortTimeLabels ? '%b' : '%B');
}
else if (timeString.indexOf('date') > -1) {
if (containsTimeUnit(timeUnit, TimeUnit.DAY)) {
dateComponents.push(shortTimeLabels ? '%a' : '%A');
}
else if (containsTimeUnit(timeUnit, TimeUnit.DATE)) {
dateComponents.push('%d');
}
var timeComponents = [];
if (timeString.indexOf('hours') > -1) {
if (containsTimeUnit(timeUnit, TimeUnit.HOURS)) {
timeComponents.push('%H');
}
if (timeString.indexOf('minutes') > -1) {
if (containsTimeUnit(timeUnit, TimeUnit.MINUTES)) {
timeComponents.push('%M');
}
if (timeString.indexOf('seconds') > -1) {
if (containsTimeUnit(timeUnit, TimeUnit.SECONDS)) {
timeComponents.push('%S');
}
if (timeString.indexOf('milliseconds') > -1) {
if (containsTimeUnit(timeUnit, TimeUnit.MILLISECONDS)) {
timeComponents.push('%L');

@@ -88,5 +97,17 @@ }

}
return out.length > 0 ? out.join(' ') : undefined;
if (out.length > 0) {
var template_1 = '{{' + field + ' | time:\'' + out.join(' ') + '\'}}';
return template_1.replace(new RegExp('{{' + field + ' \\| time:\'\'}}', 'g'), '');
}
else {
return undefined;
}
}
exports.format = format;
exports.template = template;
function containsTimeUnit(fullTimeUnit, timeUnit) {
var fullTimeUnitStr = fullTimeUnit.toString();
var timeUnitStr = timeUnit.toString();
return fullTimeUnitStr.indexOf(timeUnitStr) > -1;
}
exports.containsTimeUnit = containsTimeUnit;
//# sourceMappingURL=timeunit.js.map

@@ -23,2 +23,6 @@

SECONDSMILLISECONDS = 'secondsmilliseconds' as any,
QUARTER = 'quarter' as any,
YEARQUARTER = 'yearquarter' as any,
QUARTERMONTH = 'quartermonth' as any,
YEARQUARTERMONTH = 'yearquartermonth' as any,
}

@@ -47,6 +51,10 @@

TimeUnit.SECONDSMILLISECONDS,
TimeUnit.QUARTER,
TimeUnit.YEARQUARTER,
TimeUnit.QUARTERMONTH,
TimeUnit.YEARQUARTERMONTH,
];
/** returns the template name used for axis labels for a time unit */
export function format(timeUnit: TimeUnit, abbreviated = false): string {
export function template(timeUnit: TimeUnit, field: string, shortTimeLabels: boolean): string {
if (!timeUnit) {

@@ -56,17 +64,20 @@ return undefined;

let timeString = timeUnit.toString();
let dateComponents = [];
if (timeString.indexOf('year') > -1) {
dateComponents.push(abbreviated ? '%y' : '%Y');
if (containsTimeUnit(timeUnit, TimeUnit.YEAR)) {
dateComponents.push(shortTimeLabels ? '%y' : '%Y');
}
if (timeString.indexOf('month') > -1) {
dateComponents.push(abbreviated ? '%b' : '%B');
if (containsTimeUnit(timeUnit, TimeUnit.QUARTER)) {
// special template for quarter
dateComponents.push('\'}}Q{{' + field + ' | quarter}}{{' + field + ' | time:\'');
}
if (timeString.indexOf('day') > -1) {
dateComponents.push(abbreviated ? '%a' : '%A');
} else if (timeString.indexOf('date') > -1) {
if (containsTimeUnit(timeUnit, TimeUnit.MONTH)) {
dateComponents.push(shortTimeLabels ? '%b' : '%B');
}
if (containsTimeUnit(timeUnit, TimeUnit.DAY)) {
dateComponents.push(shortTimeLabels ? '%a' : '%A');
} else if (containsTimeUnit(timeUnit, TimeUnit.DATE)) {
dateComponents.push('%d');

@@ -77,12 +88,12 @@ }

if (timeString.indexOf('hours') > -1) {
if (containsTimeUnit(timeUnit, TimeUnit.HOURS)) {
timeComponents.push('%H');
}
if (timeString.indexOf('minutes') > -1) {
if (containsTimeUnit(timeUnit, TimeUnit.MINUTES)) {
timeComponents.push('%M');
}
if (timeString.indexOf('seconds') > -1) {
if (containsTimeUnit(timeUnit, TimeUnit.SECONDS)) {
timeComponents.push('%S');
}
if (timeString.indexOf('milliseconds') > -1) {
if (containsTimeUnit(timeUnit, TimeUnit.MILLISECONDS)) {
timeComponents.push('%L');

@@ -99,3 +110,16 @@ }

return out.length > 0 ? out.join(' ') : undefined;
if (out.length > 0) {
// clean up empty formatting expressions that may have been generated by the quarter time unit
const template = '{{' + field + ' | time:\'' + out.join(' ') + '\'}}';
return template.replace(new RegExp('{{' + field + ' \\| time:\'\'}}', 'g'), '');
} else {
return undefined;
}
}
/** Returns true if container contains the containee, false otherwise. */
export function containsTimeUnit(fullTimeUnit: TimeUnit, timeUnit: TimeUnit) {
let fullTimeUnitStr = fullTimeUnit.toString();
let timeUnitStr = timeUnit.toString();
return fullTimeUnitStr.indexOf(timeUnitStr) > -1;
}

@@ -15,2 +15,3 @@ "use strict";

exports.isBoolean = util_1.isBoolean;
var util_2 = require('datalib/src/util');
var generate_1 = require('datalib/src/generate');

@@ -22,5 +23,23 @@ exports.range = generate_1.range;

exports.Channel = channel_1.Channel;
var util_2 = require('datalib/src/util');
var util_3 = require('datalib/src/util');
function pick(obj, props) {
var copy = {};
props.forEach(function (prop) {
if (obj.hasOwnProperty(prop)) {
copy[prop] = obj[prop];
}
});
return copy;
}
exports.pick = pick;
function omit(obj, props) {
var copy = util_2.duplicate(obj);
props.forEach(function (prop) {
delete copy[prop];
});
return copy;
}
exports.omit = omit;
function hash(a) {
if (util_2.isString(a) || util_2.isNumber(a) || util_2.isBoolean(a)) {
if (util_3.isString(a) || util_3.isNumber(a) || util_3.isBoolean(a)) {
return String(a);

@@ -87,3 +106,3 @@ }

exports.map = map;
function any(arr, f) {
function some(arr, f) {
var i = 0;

@@ -97,4 +116,4 @@ for (var k = 0; k < arr.length; k++) {

}
exports.any = any;
function all(arr, f) {
exports.some = some;
function every(arr, f) {
var i = 0;

@@ -108,3 +127,3 @@ for (var k = 0; k < arr.length; k++) {

}
exports.all = all;
exports.every = every;
function flatten(arrays) {

@@ -111,0 +130,0 @@ return [].concat.apply([], arrays);

@@ -6,2 +6,3 @@ /// <reference path="../typings/datalib.d.ts"/>

export {keys, extend, duplicate, isArray, vals, truncate, toMap, isObject, isString, isNumber, isBoolean} from 'datalib/src/util';
import {duplicate as _duplicate} from 'datalib/src/util';
export {range} from 'datalib/src/generate';

@@ -14,2 +15,34 @@ export {has} from './encoding'

/**
* Creates an object composed of the picked object properties.
*
* Example: (from lodash)
*
* var object = { 'a': 1, 'b': '2', 'c': 3 };
* pick(object, ['a', 'c']);
* // → { 'a': 1, 'c': 3 }
*
*/
export function pick(obj: any, props: string[]) {
let copy = {};
props.forEach((prop) => {
if (obj.hasOwnProperty(prop)) {
copy[prop] = obj[prop];
}
});
return copy;
}
/**
* The opposite of _.pick; this method creates an object composed of the own
* and inherited enumerable string keyed properties of object that are not omitted.
*/
export function omit(obj: any, props: string[]) {
let copy = _duplicate(obj);
props.forEach((prop) => {
delete copy[prop];
});
return copy;
}
export function hash(a: any) {

@@ -76,3 +109,3 @@ if (isString(a) || isNumber(a) || isBoolean(a)) {

export function any<T>(arr: Array<T>, f: (d: T, k?, i?) => boolean) {
export function some<T>(arr: Array<T>, f: (d: T, k?, i?) => boolean) {
let i = 0;

@@ -87,3 +120,3 @@ for (let k = 0; k<arr.length; k++) {

export function all<T>(arr: Array<T>, f: (d: T, k?, i?) => boolean) {
export function every<T>(arr: Array<T>, f: (d: T, k?, i?) => boolean) {
let i = 0;

@@ -90,0 +123,0 @@ for (let k = 0; k<arr.length; k++) {

@@ -34,3 +34,4 @@ import {isArray} from './util';

parent?: string
} ,
},
template?: string,
scale?: string, // TODO: object

@@ -86,1 +87,10 @@ mult?: number,

export type VgTransform = any;
export interface VgStackTransform {
type: string;
offset?: any;
groupby: any;
field: any;
sortby: any;
output: any;
}

@@ -69,3 +69,2 @@ {

"src/compile/scale.ts",
"src/compile/stack.ts",
"src/compile/time.ts",

@@ -84,2 +83,3 @@ "src/compile/unit.ts",

"src/spec.ts",
"src/stack.ts",
"src/timeunit.ts",

@@ -94,2 +94,3 @@ "src/transform.ts",

"test/compile/common.test.ts",
"test/compile/timeunit.test.ts",
"test/compile/compile.test.ts",

@@ -108,3 +109,2 @@ "test/compile/data.test.ts",

"test/compile/scale.test.ts",
"test/compile/stack.test.ts",
"test/compile/unit.test.ts",

@@ -114,2 +114,4 @@ "test/fielddef.test.ts",

"test/spec.test.ts",
"test/timeunit.test.ts",
"test/stack.test.ts",
"test/type.test.ts",

@@ -116,0 +118,0 @@ "test/util.ts",

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc