Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add properties to Encoding Customizer -- WIP #823

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 45 additions & 13 deletions src/components/encoding-pane/property-editor-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,13 @@ export interface StringSchema {
default?: string;
}

export interface BooleanSchema {
type: 'boolean';
title: string;
enum?: string[];
default?: boolean;
}

export interface IntegerSchema {
type: 'number';
title: string;
Expand All @@ -39,7 +46,7 @@ export function isStringSchema(schema: SchemaProperty): schema is StringSchema {
return schema.type === 'string';
}

export type SchemaProperty = ObjectSchema | StringSchema | IntegerSchema;
export type SchemaProperty = ObjectSchema | StringSchema | IntegerSchema | BooleanSchema;

export interface UISchema {
[key: string]: UISchemaItem;
Expand All @@ -66,7 +73,10 @@ export const CUSTOMIZABLE_ENCODING_CHANNELS = [Channel.X, Channel.Y, Channel.COL
// Key is Tab name, value is list of fieldDef properties
// ------------------------------------------------------------------------------

const AXIS_ORIENT_TITLE = ['title', 'orient'].map(p => ({prop: 'axis', nestedProp: p}));
const AXIS_ORIENT_TITLE = ['title', 'orient'].map(p =>
({prop: 'axis', nestedProp: p}));
const AXIS_ADVANCED_PROPS = ['title', 'orient', 'grid', 'domain', 'labels', 'ticks', 'labelAngle'].map(p =>
({prop: 'axis', nestedProp: p}));
const LEGEND_ORIENT_TITLE = ['orient', 'title'].map(p => ({prop: 'legend', nestedProp: p}));

const POSITION_FIELD_NOMINAL_INDEX = {
Expand All @@ -76,6 +86,9 @@ const POSITION_FIELD_NOMINAL_INDEX = {
nestedProp: 'type'
},
...AXIS_ORIENT_TITLE
],
'Axis': [
...AXIS_ADVANCED_PROPS
]
};

Expand All @@ -85,6 +98,10 @@ const POSITION_FIELD_QUANTITATIVE_INDEX = {
'Common': [
...POSITION_FIELD_NOMINAL_INDEX.Common,
{prop: 'stack'}
],
'Axis': [
...AXIS_ADVANCED_PROPS,
{prop: 'axis', nestedProp: 'format'}
]
};

Expand Down Expand Up @@ -128,13 +145,13 @@ export function generatePropertyEditorSchema(prop: string, nestedProp: string, p
return generateAxisEditorSchema(nestedProp as keyof Axis, channel, title, propertyKey);

case 'stack':
return generateSelectSchema('stack', (vlSchema as any).definitions.StackOffset.enum, title);
return generateSelectSchema('stack', (vlSchema as any).definitions.StackOffset.enum, title, 'string');

case 'legend':
return generateLegendEditorSchema(nestedProp as keyof Legend, title, propertyKey);

case 'format':
return generateTextBoxSchema('format', '', title, 'string');
return generateTextBoxSchema('format', 'D3 format pattern', title, 'string');

default:
throw new Error('Property combination not recognized');
Expand All @@ -144,13 +161,14 @@ export function generatePropertyEditorSchema(prop: string, nestedProp: string, p
function generateLegendEditorSchema(legendProp: keyof Legend, title: string, propertyKey: string) {
switch (legendProp) {
case 'orient':
return generateSelectSchema(propertyKey, (vlSchema as any).definitions.LegendOrient.enum, title);
return generateSelectSchema(propertyKey, (vlSchema as any).definitions.LegendOrient.enum, title, 'string');

case 'title':
return generateTextBoxSchema(propertyKey, '', title, 'string');

case 'type':
return generateSelectSchema(propertyKey, (vlSchema as any).definitions.Legend.properties.type.enum, title);
return generateSelectSchema(propertyKey, (vlSchema as any).definitions.Legend.properties.type.enum, title,
'string');

default:
throw new Error('Property combination not recognized');
Expand All @@ -160,11 +178,24 @@ function generateLegendEditorSchema(legendProp: keyof Legend, title: string, pro
function generateAxisEditorSchema(axisProp: keyof Axis, channel: Channel, title: string, propertyKey: string) {
switch (axisProp) {
case 'orient':
return generateSelectSchema(propertyKey, channel === 'y' ? ['left', 'right'] : ['top', 'bottom'], title);
return generateSelectSchema(propertyKey, channel === 'y' ? ['left', 'right'] : ['top', 'bottom'], title,
'string');

case 'title':
return generateTextBoxSchema(propertyKey, '', title, 'string');

case 'format':
return generateTextBoxSchema('format', '', title, 'string');

case 'labelAngle':
return generateTextBoxSchema(propertyKey, '', title, 'number');

case 'grid':
case 'domain':
case 'labels':
case 'ticks':
return generateSelectSchema(propertyKey, undefined, title, 'boolean');

default:
throw new Error('Property combination not recognized');
}
Expand All @@ -174,11 +205,11 @@ function generateScaleEditorSchema(scaleProp: keyof Scale, scaleTypes: string[],
title: string, propertyKey: string) {
switch (scaleProp) {
case 'type':
return generateSelectSchema(propertyKey, scaleTypes, title);
return generateSelectSchema(propertyKey, scaleTypes, title, 'string');

case 'scheme':
return generateSelectSchema(propertyKey, isContinuous(fieldDef) ? SEQUENTIAL_COLOR_SCHEMES :
CATEGORICAL_COLOR_SCHEMES, title);
CATEGORICAL_COLOR_SCHEMES, title, 'string');

case 'range':
case 'domain':
Expand Down Expand Up @@ -232,15 +263,16 @@ function getSupportedScaleTypes(channel: Channel, fieldDef: ShelfFieldDef): stri
}
}

function generateSelectSchema(propertyKey: string, enumVals: string[], title: string) {
function generateSelectSchema(propertyKey: string, enumVals: string[] | boolean[], title: string,
primitiveType: 'string' | 'boolean') {
const schema: ObjectSchema = {
type: 'object',
properties: {
[propertyKey]: {
type: 'string',
type: primitiveType,
title: title,
enum: enumVals
}
} as SchemaProperty
}
};

Expand Down Expand Up @@ -312,7 +344,7 @@ export function generateFormData(shelfId: ShelfId, fieldDef: ShelfFieldDef) {
const formData = fieldDef[prop] ? nestedProp ? fieldDef[prop][nestedProp] : fieldDef[prop] : undefined;
// Display empty string when '?' is passed in to retrieve default value
// '?' is passed when formData is empty to avoid passing in empty string as a property/nestedProp value
formDataIndex[propertyKey] = formData === undefined ? '' : formData;
formDataIndex[propertyKey] = formData;
}
}

Expand Down