-
Notifications
You must be signed in to change notification settings - Fork 167
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
Data faceting #538
base: kb-MENG
Are you sure you want to change the base?
Data faceting #538
Changes from all commits
1949056
21394ee
bde9678
f0671b6
a1b3a83
d05fcc1
26ea74e
2b26d53
10ebfda
ae32532
21abfce
4449e62
db08fe8
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 |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import {createStandardAction} from 'typesafe-actions'; | ||
import {FacetLayoutRecord} from '../store/factory/FacetLayout'; | ||
import {assignId} from '../util/counter'; | ||
import {State} from '../store'; | ||
import {Dispatch} from 'redux'; | ||
|
||
export function addFacetLayout (payload: FacetLayoutRecord) { | ||
return function(dispatch: Dispatch, getState: () => State) { | ||
const id = payload._id || assignId(dispatch, getState()); | ||
dispatch(baseAddFacetLayout(payload.merge({_id: id}), id)); | ||
}; | ||
} | ||
|
||
export const baseAddFacetLayout = createStandardAction('ADD_FACET_LAYOUT')<FacetLayoutRecord, number>(); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
import * as React from 'react'; | ||
import { connect } from 'react-redux'; | ||
import {State} from '../../store'; | ||
import {FieldDraggingStateRecord} from '../../store/factory/Inspector'; | ||
// import {GroupFacet} from "../../store/factory/marks/Group"; | ||
import {Facet} from 'vega-typings'; | ||
import {getClosestGroupId} from '../../util/hierarchy'; | ||
import {addFacetLayout} from '../../actions/facetLayoutActions'; | ||
import {addFacet} from '../../actions/markActions'; | ||
import {FacetLayout} from '../../store/factory/FacetLayout'; | ||
interface StateProps { | ||
dragging: FieldDraggingStateRecord; | ||
groupId: number; | ||
} | ||
|
||
interface OwnProps { | ||
layoutOrientation: string | ||
} | ||
interface DispatchProps { | ||
facetField: (field: string, datasetId: number, groupId: number) => void; | ||
} | ||
|
||
function mapStateToProps(state: State): StateProps { | ||
const groupId = getClosestGroupId(); | ||
|
||
const draggingRecord = state.getIn(['inspector', 'dragging']); | ||
const isFieldDrag = draggingRecord && (draggingRecord as FieldDraggingStateRecord).dsId; | ||
|
||
return { | ||
dragging: isFieldDrag ? draggingRecord : null, | ||
groupId | ||
}; | ||
} | ||
|
||
function mapDispatchToProps(dispatch, ownProps: OwnProps): DispatchProps { | ||
return { | ||
facetField: (field, datasetId, groupId) => { | ||
let numCols; | ||
if (ownProps.layoutOrientation == "Column") { | ||
numCols = 1; | ||
} else { | ||
numCols = null; | ||
} | ||
dispatch(addFacetLayout(FacetLayout({columns: numCols}))); | ||
// dispatch(addGroupFacet(GroupFacet({facet: {name: "facet", data: "cars_source_5", groupby: [field]}}), groupId)); // remove hardcoded data name | ||
dispatch(addFacet({name: "facet",data: String(datasetId), groupby: field} as Facet, groupId)); | ||
} | ||
} | ||
} | ||
|
||
class FacetDropzone extends React.Component<StateProps & OwnProps & DispatchProps> { | ||
|
||
public handleDragOver = (evt) => { | ||
if (evt.preventDefault) { | ||
evt.preventDefault(); | ||
} | ||
|
||
return false; | ||
}; | ||
|
||
public handleDrop = () => { | ||
this.props.facetField(this.props.dragging.fieldDef.name, this.props.dragging.dsId, this.props.groupId); | ||
}; | ||
|
||
public render() { | ||
if (!this.props.dragging) return null; | ||
return ( | ||
<div className="facet-dropzone" onDragOver={(e) => this.handleDragOver(e)} onDrop={() => this.handleDrop()}> | ||
<div><i>Facet {this.props.layoutOrientation}</i></div> | ||
</div> | ||
); | ||
} | ||
|
||
} | ||
|
||
export default connect(mapStateToProps, mapDispatchToProps)(FacetDropzone); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import * as React from 'react'; | ||
import { connect } from 'react-redux'; | ||
import {State} from '../../store'; | ||
import FacetDropzone from './FacetDropzone'; | ||
|
||
const layoutOrientaions = ['Row', 'Column']; | ||
interface StateProps { | ||
layouts: number[]; | ||
} | ||
|
||
function mapStateToProps(state: State): StateProps { | ||
const layoutList = state.getIn(['vis', 'present', 'layouts']); | ||
return { | ||
layouts: Array.from(layoutList.keys()) | ||
}; | ||
} | ||
|
||
class FacetOptionsHolder extends React.Component<StateProps> { | ||
public render() { | ||
|
||
return ( | ||
<div className='facet-container'> | ||
{layoutOrientaions.map(function(dir,i) { | ||
return ( | ||
<FacetDropzone key={i} layoutOrientation={dir}/> | ||
); | ||
}, this)} | ||
</div> | ||
)} | ||
|
||
} | ||
|
||
export default connect(mapStateToProps, null)(FacetOptionsHolder); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import {Map} from 'immutable'; | ||
import {ActionType, getType} from 'typesafe-actions'; | ||
import {FacetLayoutState} from '../store/factory/FacetLayout'; | ||
import * as FacetLayoutActions from '../actions/facetLayoutActions'; | ||
|
||
/** | ||
* This reducer handles layout updates | ||
* @param {Object} state - An Immutable state object | ||
* @param {Object} action - An action object | ||
*/ | ||
export function facetLayoutsReducer(state: FacetLayoutState, | ||
action: ActionType<typeof FacetLayoutActions>): FacetLayoutState { | ||
const id = String(action.meta); | ||
|
||
if (typeof state === 'undefined') { | ||
return Map(); | ||
} | ||
|
||
if (action.type === getType(FacetLayoutActions.baseAddFacetLayout)) { | ||
return state.set(id, action.payload); | ||
} | ||
|
||
return state; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import {Map, Record, RecordOf} from 'immutable'; | ||
|
||
/** | ||
* Layouts align multiple groups | ||
*/ | ||
export interface FacetLayout { | ||
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. is there enough overlap between FacetLayout and Layout that we can think about e.g.:
i'm not suggesting either particular choice is more right here but consider whether or not that might simplify things in some places (it also might not simplify things at all, in which case feel free to reject this idea) 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. Interesting, they are similar in concept but very different in implementation and how they are used in Lyra and the ultimate vega spec. Perhaps worth discussing further |
||
/** | ||
* The Lyra ID of this vega layout. | ||
*/ | ||
_id: number; | ||
/** | ||
* Number of columns in this layout. | ||
*/ | ||
columns: number; | ||
/** | ||
* Spacing between groups in this layout. | ||
*/ | ||
padding: number; | ||
/** | ||
* Bounds for this layout. | ||
*/ | ||
bounds: string; | ||
/** | ||
* Group alignment for this layout. | ||
*/ | ||
align: string; | ||
|
||
} | ||
|
||
export const FacetLayout = Record<FacetLayout>({ | ||
_id: null, | ||
columns: null, | ||
padding: 30, | ||
bounds: "full", | ||
align: "all" | ||
}, 'FacetLayout'); | ||
|
||
export type FacetLayoutRecord = RecordOf<FacetLayout>; | ||
|
||
export type FacetLayoutState = FacetLayoutRecord; | ||
|
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.
re: this file, facetLayoutReducer, and facetLayout.ts, i think they're related enough to core layout functionality that i would consider just adding the facet actions / reducer cases / record definitions to the existing layout files so that it's easier to find everything.