diff --git a/src/js/components/encodings/ScaleList.tsx b/src/js/components/encodings/ScaleList.tsx index d540058d3..a9b00e138 100644 --- a/src/js/components/encodings/ScaleList.tsx +++ b/src/js/components/encodings/ScaleList.tsx @@ -8,14 +8,21 @@ import sg from '../../ctrl/signals'; import {channelName} from '../../actions/bindChannel'; import {MODE, SELECTED, CELL} from '../../store/factory/Signal'; import {ScaleDraggingState, DraggingStateRecord, ScaleDraggingStateRecord} from '../../store/factory/Inspector'; -import {startDragging, stopDragging} from '../../actions/inspectorActions'; +import { startDragging, stopDragging} from '../../actions/inspectorActions'; import {setMarkVisual} from '../../actions/markActions'; import {NumericValueRef, StringValueRef, tupleid} from 'vega'; +import { deleteScale } from '../../actions/scaleActions'; +import { Icon } from '../Icon'; +import ReactTooltip from 'react-tooltip'; +import { ThunkDispatch } from 'redux-thunk'; +import { AnyAction } from 'redux'; const ctrl = require('../../ctrl'); const imutils = require('../../util/immutable-utils'); const getInVis = imutils.getInVis; +const assets = require('../../util/assets'); +const capitalize = require('capitalize'); interface StateProps { selectedId: number; @@ -28,6 +35,7 @@ interface DispatchProps { startDragging: (d: DraggingStateRecord) => void; stopDragging: () => void; setMarkVisual: (payload: {property: string, def: NumericValueRef | StringValueRef}, markId: number) => void; + deleteScale: (_: any, id: number, evt: any) => void; } function mapStateToProps(reduxState: State, ownProps): StateProps { @@ -40,7 +48,28 @@ function mapStateToProps(reduxState: State, ownProps): StateProps { }; } -const actionCreators: DispatchProps = {startDragging, stopDragging, selectScale, setMarkVisual}; +function mapDispatchToProps(dispatch: ThunkDispatch): DispatchProps { + return { + startDragging: function (d) { + dispatch(startDragging(d)); + }, + stopDragging: function () { + dispatch(stopDragging()); + }, + selectScale: function (guideId) { + dispatch(selectScale(guideId)); + }, + setMarkVisual: function (payload, markId) { + dispatch(setMarkVisual(payload, markId)); + }, + deleteScale: function (selectedId, scaleId, evt) { + dispatch(deleteScale(null, scaleId)); + evt.preventDefault(); + evt.stopPropagation(); + ReactTooltip.hide(); + }, + }; +} class ScaleList extends React.Component { private handleDragStart = (evt) => { @@ -86,12 +115,17 @@ class ScaleList extends React.Component { ctrl.update(); } } + + public componentDidUpdate() { + ReactTooltip.rebuild(); + } + public render() { const props = this.props; const scales = [...props.scales.values()] return ( -
+

Scales

    {scales.map((scale) => { @@ -109,7 +143,12 @@ class ScaleList extends React.Component { data-scale={scale.get('_id')} data-field={field}> {/* */} - {name} +
    + {capitalize(name)} +
    +
); @@ -120,4 +159,4 @@ class ScaleList extends React.Component { } } -export default connect(mapStateToProps, actionCreators)(ScaleList); +export default connect(mapStateToProps, mapDispatchToProps)(ScaleList); diff --git a/src/js/reducers/marksReducer.ts b/src/js/reducers/marksReducer.ts index 0dfa6a114..071d8649a 100644 --- a/src/js/reducers/marksReducer.ts +++ b/src/js/reducers/marksReducer.ts @@ -2,6 +2,7 @@ import {Map} from 'immutable'; import {ActionType, getType} from 'typesafe-actions'; import * as helperActions from '../actions/bindChannel/helperActions'; import * as guideActions from '../actions/guideActions'; +import * as scaleActions from '../actions/scaleActions'; import * as markActions from '../actions/markActions'; import * as sceneActions from '../actions/sceneActions'; import * as interactionActions from '../actions/interactionActions'; @@ -29,7 +30,7 @@ const ensureValuePresentImmutable = function(state: MarkState, path: string[], v }; const ensureValueAbsent = function(state: MarkState, path: string[], valToRemove): MarkState { - return state.updateIn(path, children => children.filter(c => c !== valToRemove)); + return state.updateIn(path, children => children != null ? children.filter(c => c !== valToRemove) : children); }; // Helper reducer to add a mark to the store. Runs the mark through a method to @@ -155,6 +156,7 @@ export function marksReducer( | ActionType | ActionType | ActionType + | ActionType ): MarkState { if (typeof state === 'undefined') { return Map(); @@ -257,6 +259,24 @@ export function marksReducer( return ensureValueAbsent(state, [String(action.payload.groupId), 'legends'], id); } + if (action.type === getType(scaleActions.deleteScale)) { + const groupIds = state.keySeq().toArray(); + groupIds.forEach(function (groupId) { + state = ensureValueAbsent(state, [String(groupId), 'scales'], id); + + // clean up encoding references + let encodingKeys = Object.keys(state.getIn([String(groupId), 'encode', 'update'])); + encodingKeys.forEach(function (encodingKey) { + let needsDelete = state.getIn([String(groupId), 'encode', 'update', encodingKey, 'scale']) === id; + if (needsDelete) { + state = state.setIn([String(groupId), 'encode', 'update', encodingKey], undefined); + } + }); + + }); + return state; + } + if (action.type === getType(interactionActions.deleteInteraction)) { return ensureValueAbsent(state, [String(action.payload.groupId), '_interactions'], id); } diff --git a/src/scss/layers.scss b/src/scss/layers.scss index 06676f268..736be7039 100644 --- a/src/scss/layers.scss +++ b/src/scss/layers.scss @@ -28,16 +28,16 @@ } li { - float: left; margin: $inner-padding; margin-top: 0; list-style-type: none; } .scale.name { - display: inline-block; - padding: $inner-padding; + display: flex; + padding: 2*$inner-padding; text-align: center; + border-radius: 2px; background-color: skyblue; color: black;