-
Notifications
You must be signed in to change notification settings - Fork 178
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
WIP -- Value Def Customization UI #827
base: master
Are you sure you want to change the base?
Changes from 8 commits
5d94347
db83899
f181885
0f39e9e
56250f7
35834bb
1a0d6be
ab0fa6c
a38776a
442cb13
2bbe79e
2564e6d
c272d90
acbc7fb
7e7f3d4
5da835b
ce3d684
1b97be5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,7 @@ import * as CSSModules from 'react-css-modules'; | |
import {ConnectDropTarget, DropTarget, DropTargetCollector, DropTargetSpec} from 'react-dnd'; | ||
import * as TetherComponent from 'react-tether'; | ||
import {contains} from 'vega-lite/build/src/util'; | ||
import {isValueDef} from '../../../node_modules/vega-lite/build/src/fielddef'; | ||
import {ActionHandler} from '../../actions/index'; | ||
import { | ||
SPEC_FIELD_ADD, SPEC_FIELD_MOVE, SPEC_FIELD_REMOVE, SPEC_FUNCTION_ADD_WILDCARD, | ||
|
@@ -21,6 +22,7 @@ import * as styles from './encoding-shelf.scss'; | |
import {FieldCustomizer} from './field-customizer'; | ||
import {FunctionPicker, FunctionPickerWildcardHandler} from './function-picker'; | ||
import {CUSTOMIZABLE_ENCODING_CHANNELS} from './property-editor-schema'; | ||
import {ValueCustomizer} from './value-customizer'; | ||
|
||
/** | ||
* Props for react-dnd of EncodingShelf | ||
|
@@ -50,7 +52,7 @@ export interface EncodingShelfState { | |
} | ||
class EncodingShelfBase extends React.PureComponent< | ||
EncodingShelfProps, EncodingShelfState | ||
> implements FunctionPickerWildcardHandler { | ||
> implements FunctionPickerWildcardHandler { | ||
private fieldCustomizer: HTMLElement; | ||
private encodingShelf: HTMLElement; | ||
|
||
|
@@ -79,7 +81,7 @@ class EncodingShelfBase extends React.PureComponent< | |
} | ||
|
||
public render() { | ||
const {id, connectDropTarget, fieldDef, handleAction} = this.props; | ||
const {id, connectDropTarget, fieldDef, valueDef, handleAction} = this.props; | ||
|
||
const isWildcardShelf = isWildcard(id.channel); | ||
const channelName = isWildcardShelf ? 'any' : id.channel; | ||
|
@@ -91,27 +93,35 @@ class EncodingShelfBase extends React.PureComponent< | |
attachment="top left" | ||
targetAttachment="bottom left" | ||
> | ||
{(fieldDef && !isWildcardChannelId(id) && contains(CUSTOMIZABLE_ENCODING_CHANNELS, id.channel)) ? | ||
{(!isWildcardChannelId(id) && contains(CUSTOMIZABLE_ENCODING_CHANNELS, id.channel)) ? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since we don't allow customizing x and y valuedef, caret shouldn't be shown for x and y if there is no fieldDef. |
||
<span onClick={this.toggleCustomizer} ref={this.fieldHandler}> | ||
{channelName}{' '} <i className={'fa fa-caret-down'}/> | ||
{channelName}{' '} <i className={'fa fa-caret-down'} /> | ||
</span> : | ||
<span> | ||
{channelName} | ||
</span> | ||
} | ||
|
||
{this.state.customizerIsOpened && | ||
<div ref={this.popupRefHandler}> | ||
<FieldCustomizer | ||
shelfId={id} | ||
fieldDef={fieldDef} | ||
handleAction={handleAction} | ||
/> | ||
</div> | ||
<div ref={this.popupRefHandler}> | ||
{ (!fieldDef && !valueDef) || isValueDef(valueDef) ? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not just There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed! The issue was here: https://github.com/vega/voyager/blob/master/src/components/encoding-pane/index.tsx#L117 I fixed this by adding appropriate typeguarding and the basic |
||
<ValueCustomizer | ||
shelfId={id} | ||
valueDef={valueDef} | ||
handleAction={handleAction} | ||
/> : | ||
<FieldCustomizer | ||
shelfId={id} | ||
fieldDef={fieldDef} | ||
handleAction={handleAction} | ||
/> | ||
} | ||
</div> | ||
} | ||
</TetherComponent> | ||
</div> | ||
{fieldDef ? this.renderField() : this.renderFieldPlaceholder()} | ||
{valueDef && valueDef.value ? this.renderFieldPlaceholder() : fieldDef ? this.renderField() : | ||
this.renderFieldPlaceholder()} | ||
</div> | ||
); | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
.value-customizer { | ||
background-color: #eee; | ||
border-bottom: 5px solid #eee; | ||
border-radius: 3px; | ||
width: 190px; | ||
|
||
select { | ||
font-size: 10px; | ||
} | ||
|
||
fieldset { | ||
border: 0; | ||
padding-bottom: 10px; | ||
padding-top: 10px; | ||
} | ||
|
||
form { | ||
height: 3.1em; | ||
} | ||
|
||
select option{ | ||
font-size: 10px; | ||
} | ||
|
||
option { | ||
font-size: 11px; | ||
} | ||
|
||
label { | ||
display: inline-block; | ||
font-size: 11px !important; // cannot access react-form's css attributes, so have to use important | ||
padding-right: 10px; | ||
text-align: left; | ||
width: 75px; | ||
} | ||
|
||
ul { | ||
border-bottom: 1px solid #aaa; | ||
margin: 0 0; | ||
padding: 2px; | ||
height: 18px; | ||
} | ||
|
||
li { | ||
display: inline-block; | ||
border: 1px solid transparent; | ||
border-bottom: none; | ||
bottom: -1px; | ||
position: relative; | ||
list-style: none; | ||
padding: 2px 10px; | ||
cursor: pointer; | ||
font-size: 12px; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import * as React from 'react'; | ||
import * as CSSModules from 'react-css-modules'; | ||
import Form from 'react-jsonschema-form'; | ||
import {debounce} from 'throttle-debounce'; | ||
import {Channel} from '../../../node_modules/vega-lite/build/src/channel'; | ||
import {ActionHandler, SPEC_VALUE_CHANGE, SpecEncodingAction} from "../../actions"; | ||
import {ShelfId, ShelfValueDef} from "../../models"; | ||
import * as styles from './value-customizer.scss'; | ||
import {generateValueDefFormData, generateValueEditorSchema} from './value-editor-schema'; | ||
|
||
export interface ValueCustomizerProps extends ActionHandler<SpecEncodingAction> { | ||
shelfId: ShelfId; | ||
valueDef: ShelfValueDef; | ||
} | ||
|
||
export class ValueCustomizerBase extends React.PureComponent<ValueCustomizerProps, {}> { | ||
|
||
constructor(props: ValueCustomizerProps) { | ||
super(props); | ||
this.changeValue = this.changeValue.bind(this); | ||
this.changeValue = debounce(500, this.changeValue); | ||
} | ||
public render() { | ||
const {shelfId, valueDef} = this.props; | ||
// TODO: refactor to generic function to generate schema & uischema | ||
const formData = generateValueDefFormData(shelfId, valueDef) || {}; | ||
const {schema, uiSchema} = generateValueEditorSchema(shelfId.channel as Channel); | ||
return ( | ||
<div styleName="value-customizer"> | ||
<Form | ||
schema={schema} | ||
uiSchema={uiSchema} | ||
formData={formData} | ||
onChange={this.changeValue} | ||
> | ||
<button type="submit" style={{display: 'none'}}>Submit</button> | ||
</Form> | ||
</div> | ||
); | ||
} | ||
|
||
protected changeValue(result: any) { | ||
const value = result.formData[Object.keys(result.formData)[0]].toString(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why |
||
const {shelfId, handleAction} = this.props; | ||
const valueDef: ShelfValueDef = {value}; | ||
|
||
handleAction({ | ||
type: SPEC_VALUE_CHANGE, | ||
payload: { | ||
shelfId, | ||
valueDef | ||
} | ||
}); | ||
} | ||
} | ||
|
||
export const ValueCustomizer = CSSModules(ValueCustomizerBase, styles); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import {Channel} from "vega-lite/build/src/channel"; | ||
import {ShelfId, ShelfValueDef} from "../../models"; | ||
import {generateColorPickerSchema, generateSelectSchema, | ||
generateSliderSchema, generateTextBoxSchema} from "./property-editor-schema"; | ||
|
||
const SHAPE_VALUES = ['circle', 'square', 'cross', 'diamond', 'triangle-up', 'triangle-down', ]; | ||
|
||
export function generateValueDefFormData(shelfId: ShelfId, valueDef: ShelfValueDef) { | ||
return {[shelfId.channel.toString()]: valueDef ? valueDef.value : undefined}; | ||
} | ||
|
||
export function generateValueEditorSchema(channel: Channel): any { | ||
switch (channel) { | ||
case 'color': | ||
return generateColorPickerSchema(channel, undefined); | ||
case 'shape': | ||
return generateSelectSchema(channel, SHAPE_VALUES, undefined); | ||
case 'text': | ||
return generateTextBoxSchema(channel, 'Some Text...', undefined, 'string'); | ||
case 'size': | ||
return generateSliderSchema(channel, 1, 100); | ||
default: | ||
return {}; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,7 @@ | ||
|
||
import {Query} from 'compassql/build/src/query/query'; | ||
import {isWildcard, SHORT_WILDCARD} from 'compassql/build/src/wildcard'; | ||
import {isValueQuery} from '../../node_modules/compassql/build/src/query/encoding'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. node_modules |
||
import {QueryCreator} from './base'; | ||
import {makeWildcard} from './common'; | ||
|
||
|
@@ -16,7 +17,7 @@ export const alternativeEncodings: QueryCreator = { | |
...query.spec, | ||
mark: makeWildcard(mark), | ||
encodings: encodings.map(encQ => { | ||
if (isWildcard(encQ.channel)) { | ||
if (isWildcard(encQ.channel) || isValueQuery(encQ)) { | ||
return encQ; | ||
} | ||
return { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove
../../../node_modules/
. Please also check if you have accidentally includednode_modules
like this in other places too. :)