From 8c1c6387c96d58817a0d675c896e7feab60e3612 Mon Sep 17 00:00:00 2001 From: Thomas Nordquist Date: Mon, 17 Jun 2019 18:08:35 +0200 Subject: [PATCH] Add colors and move capability to charts --- app/src/actions/Charts.ts | 12 ++++ app/src/components/ChartPanel/Chart.tsx | 1 + .../ChartSettings/ColorSettings.tsx | 71 +++++++++++++++++++ .../ChartSettings/InterpolationSettings.tsx | 4 +- .../ChartPanel/ChartSettings/MoveUp.tsx | 35 +++++++++ .../ChartSettings/RangeSettings.tsx | 8 +-- .../ChartPanel/ChartSettings/Size.tsx | 53 ++++++++++++++ .../ChartPanel/ChartSettings/colors.ts | 46 ++++++++++++ .../ChartPanel/ChartSettings/index.tsx | 34 ++++++++- app/src/components/ChartPanel/index.tsx | 15 +++- app/src/components/Sidebar/PlotHistory.tsx | 13 ++-- app/src/components/TopicPlot.tsx | 3 +- app/src/reducers/Charts.ts | 26 ++++++- 13 files changed, 301 insertions(+), 20 deletions(-) create mode 100644 app/src/components/ChartPanel/ChartSettings/ColorSettings.tsx create mode 100644 app/src/components/ChartPanel/ChartSettings/MoveUp.tsx create mode 100644 app/src/components/ChartPanel/ChartSettings/Size.tsx create mode 100644 app/src/components/ChartPanel/ChartSettings/colors.ts diff --git a/app/src/actions/Charts.ts b/app/src/actions/Charts.ts index 3e4ede7..9e11e49 100644 --- a/app/src/actions/Charts.ts +++ b/app/src/actions/Charts.ts @@ -106,6 +106,18 @@ export const removeChart = (chartParameters: ChartParameters) => async ( dispatch(saveCharts()) } +export const moveChartUp = (parameters: { topic: string; dotPath?: string }) => async ( + dispatch: Dispatch, + getState: () => AppState +) => { + dispatch({ + topic: parameters.topic, + dotPath: parameters.dotPath, + type: ActionTypes.CHARTS_MOVE_UP, + }) + dispatch(saveCharts()) +} + export const setCharts = (charts: Array): Action => { return { charts, diff --git a/app/src/components/ChartPanel/Chart.tsx b/app/src/components/ChartPanel/Chart.tsx index 8b29682..4e5a6c0 100644 --- a/app/src/components/ChartPanel/Chart.tsx +++ b/app/src/components/ChartPanel/Chart.tsx @@ -53,6 +53,7 @@ function Chart(props: Props) {
{treeNode ? ( = createColors() + +function ColorSettings(props: { + chart: ChartParameters + actions: { + chart: typeof chartActions + } + anchorEl?: Element + open: boolean + close: () => void +}) { + const setColor = React.useCallback( + (color?: string) => props.actions.chart.updateChart(chartParametersForColor(props.chart, color)), + [props.chart] + ) + + const menuItems = React.useMemo(() => { + return colors.map(color => ( + setColor(color)} + > + {props.chart.color === color ? 'X' : ''} + + )) + }, [colors, props.chart]) + + return ( + + setColor()} + selected={props.chart.color === undefined} + > + default + + {menuItems} + + ) +} + +const mapDispatchToProps = (dispatch: any) => { + return { + actions: { + chart: bindActionCreators(chartActions, dispatch), + }, + } +} + +export default connect( + undefined, + mapDispatchToProps +)(ColorSettings) diff --git a/app/src/components/ChartPanel/ChartSettings/InterpolationSettings.tsx b/app/src/components/ChartPanel/ChartSettings/InterpolationSettings.tsx index 35c3d29..6ac6757 100644 --- a/app/src/components/ChartPanel/ChartSettings/InterpolationSettings.tsx +++ b/app/src/components/ChartPanel/ChartSettings/InterpolationSettings.tsx @@ -23,7 +23,7 @@ function InterpolationSettings(props: { } anchorEl?: Element open: boolean - onClose: () => void + close: () => void }) { const callbacks = React.useMemo(() => { const createCurveCallback = (curve: PlotCurveTypes) => () => { @@ -46,7 +46,7 @@ function InterpolationSettings(props: { }, [curves, props.chart]) return ( - + {menuItems} ) diff --git a/app/src/components/ChartPanel/ChartSettings/MoveUp.tsx b/app/src/components/ChartPanel/ChartSettings/MoveUp.tsx new file mode 100644 index 0000000..9b542f9 --- /dev/null +++ b/app/src/components/ChartPanel/ChartSettings/MoveUp.tsx @@ -0,0 +1,35 @@ +import * as React from 'react' +import { ChartParameters } from '../../../reducers/Charts' +import { Menu, MenuItem, TextField, Typography } from '@material-ui/core' +import { connect } from 'react-redux' +import { bindActionCreators } from 'redux' +import { chartActions } from '../../../actions' + +function MoveUp(props: { actions: { chart: typeof chartActions }; chart: ChartParameters; close: () => void }) { + const moveUp = React.useCallback(() => { + props.actions.chart.moveChartUp({ + topic: props.chart.topic, + dotPath: props.chart.dotPath, + }) + props.close() + }, [props.chart]) + + return ( + + Move up + + ) +} + +const mapDispatchToProps = (dispatch: any) => { + return { + actions: { + chart: bindActionCreators(chartActions, dispatch), + }, + } +} + +export default connect( + undefined, + mapDispatchToProps +)(MoveUp) diff --git a/app/src/components/ChartPanel/ChartSettings/RangeSettings.tsx b/app/src/components/ChartPanel/ChartSettings/RangeSettings.tsx index 5da5f4f..12293c5 100644 --- a/app/src/components/ChartPanel/ChartSettings/RangeSettings.tsx +++ b/app/src/components/ChartPanel/ChartSettings/RangeSettings.tsx @@ -34,13 +34,7 @@ function RangeSettings(props: { const setFromHandler = React.useCallback((e: React.ChangeEvent) => setRangeFrom(e.target.value), []) const setToHandler = React.useCallback((e: React.ChangeEvent) => setRangeTo(e.target.value), []) return ( - + Define custom ranges for the Y-Axis
void +}) { + const setChartWidth = (width?: 'big' | 'medium' | 'small') => () => { + props.actions.chart.updateChart({ + width, + topic: props.chart.topic, + dotPath: props.chart.dotPath, + }) + props.close() + } + + return ( + + + auto + + + 100% width + + + 50% width + + + 33% width + + + ) +} + +const mapDispatchToProps = (dispatch: any) => { + return { + actions: { + chart: bindActionCreators(chartActions, dispatch), + }, + } +} + +export default connect( + undefined, + mapDispatchToProps +)(Size) diff --git a/app/src/components/ChartPanel/ChartSettings/colors.ts b/app/src/components/ChartPanel/ChartSettings/colors.ts new file mode 100644 index 0000000..4611837 --- /dev/null +++ b/app/src/components/ChartPanel/ChartSettings/colors.ts @@ -0,0 +1,46 @@ +import { + amber, + orange, + pink, + purple, + deepPurple, + teal, + red, + green, + lime, + indigo, + yellow, + brown, + blueGrey, +} from '@material-ui/core/colors' + +export function colors() { + function colorToInt(color: string): [number, number, number] { + const str = color.replace('#', '') + return [parseInt(str.slice(0, 2), 16), parseInt(str.slice(2, 4), 16), parseInt(str.slice(4, 6), 16)] + } + function colorCompare(colorA: string, colorB: string) { + const a = colorToInt(colorA) + const b = colorToInt(colorB) + return Math.sqrt(Math.pow(a[0] - b[0], 2) + Math.pow(a[1] - b[1], 2) + Math.pow(a[2] - b[2], 2)) + } + const colors: Array = [ + brown, + blueGrey, + amber, + orange, + pink, + purple, + deepPurple, + teal, + red, + green, + lime, + indigo, + yellow, + ] + .map(color => [color[200], color[500], color[700]]) + .reduce((a, b) => a.concat(b), []) + .sort((a, b) => colorCompare(a, b)) + return colors +} diff --git a/app/src/components/ChartPanel/ChartSettings/index.tsx b/app/src/components/ChartPanel/ChartSettings/index.tsx index 571579c..845c1f4 100644 --- a/app/src/components/ChartPanel/ChartSettings/index.tsx +++ b/app/src/components/ChartPanel/ChartSettings/index.tsx @@ -3,6 +3,9 @@ import InterpolationSettings from './InterpolationSettings' import { ChartParameters } from '../../../reducers/Charts' import { Menu, MenuItem } from '@material-ui/core' import RangeSettings from './RangeSettings' +import Size from './Size' +import MoveUp from './MoveUp' +import ColorSettings from './ColorSettings' function ChartSettings(props: { open: boolean @@ -12,21 +15,37 @@ function ChartSettings(props: { }) { const [rangeVisible, setRangeVisible] = React.useState(false) const [interpolationVisible, setInterpolationVisible] = React.useState(false) + const [sizeVisible, setSizeVisible] = React.useState(false) + const [colorVisible, setColorVisible] = React.useState(false) const toggleRange = React.useCallback(() => { - if (!rangeVisible && open) { + if (open) { props.close() } setRangeVisible(!rangeVisible) }, [rangeVisible, open]) const toggleInterpolation = React.useCallback(() => { - if (!interpolationVisible && open) { + if (open) { props.close() } setInterpolationVisible(!interpolationVisible) }, [interpolationVisible, open]) + const toggleSize = React.useCallback(() => { + if (open) { + props.close() + } + setSizeVisible(!sizeVisible) + }, [sizeVisible, open]) + + const toggleColor = React.useCallback(() => { + if (open) { + props.close() + } + setColorVisible(!colorVisible) + }, [colorVisible, open]) + return ( @@ -36,14 +55,23 @@ function ChartSettings(props: { Curve interpolation + + Size + + + Color + + + + ) } diff --git a/app/src/components/ChartPanel/index.tsx b/app/src/components/ChartPanel/index.tsx index 760d564..fe15654 100644 --- a/app/src/components/ChartPanel/index.tsx +++ b/app/src/components/ChartPanel/index.tsx @@ -28,6 +28,19 @@ function spacingForChartCount(count: number): 4 | 6 | 12 { } } +function mapWidth(width: 'big' | 'medium' | 'small' | undefined, calculatedSpacing: 4 | 6 | 12): 4 | 6 | 12 { + switch (width) { + case 'big': + return 12 + case 'medium': + return 6 + case 'small': + return 4 + default: + return calculatedSpacing + } +} + function ChartPanel(props: Props) { const chartsInView = props.charts.count() @@ -53,7 +66,7 @@ function ChartPanel(props: Props) { timeout={{ enter: 500, exit: 500 }} classNames="example" > - + diff --git a/app/src/components/Sidebar/PlotHistory.tsx b/app/src/components/Sidebar/PlotHistory.tsx index a117f1b..33ac41b 100644 --- a/app/src/components/Sidebar/PlotHistory.tsx +++ b/app/src/components/Sidebar/PlotHistory.tsx @@ -12,6 +12,7 @@ interface Props { theme: Theme interpolation?: PlotCurveTypes range?: [number?, number?] + color?: string } function mapCurveType(type: PlotCurveTypes | undefined) { @@ -58,6 +59,12 @@ export default withTheme((props: Props) => { ? [props.range[0] || calculatedDomain[0], props.range[1] || calculatedDomain[1]] : calculatedDomain + let color: string = + props.theme.palette.type === 'light' ? props.theme.palette.secondary.dark : props.theme.palette.primary.light + if (props.color) { + color = props.color + } + return (
@@ -65,11 +72,7 @@ export default withTheme((props: Props) => { abbreviate(num)} /> + return } export default render diff --git a/app/src/reducers/Charts.ts b/app/src/reducers/Charts.ts index ef12e89..1ec2fa8 100644 --- a/app/src/reducers/Charts.ts +++ b/app/src/reducers/Charts.ts @@ -1,6 +1,7 @@ import { Action } from 'redux' import { createReducer } from './lib' import { Record, List } from 'immutable' +import MoveUp from '../components/ChartPanel/ChartSettings/MoveUp' export type PlotCurveTypes = 'curve' | 'linear' | 'cubic_basis_spline' | 'step_after' | 'step_before' @@ -12,6 +13,8 @@ export interface ChartParameters { from?: number to?: number } + width?: 'big' | 'medium' | 'small' + color?: string } export interface ChartsStateModel { @@ -20,13 +23,14 @@ export interface ChartsStateModel { export type ChartsState = Record -export type Action = AddChart | RemoveChart | SetCharts | UpdateChart +export type Action = AddChart | RemoveChart | SetCharts | UpdateChart | MoveUp export enum ActionTypes { CHARTS_ADD = 'CHARTS_ADD', CHARTS_REMOVE = 'CHARTS_REMOVE', CHARTS_SET = 'CHARTS_SET', CHARTS_UPDATE = 'CHARTS_UPDATE', + CHARTS_MOVE_UP = 'CHARTS_MOVE_UP', } export interface AddChart { @@ -34,6 +38,12 @@ export interface AddChart { chart: ChartParameters } +export interface MoveUp { + type: ActionTypes.CHARTS_ADD + topic: string + dotPath?: string +} + export interface UpdateChart { type: ActionTypes.CHARTS_ADD topic: string @@ -60,12 +70,26 @@ export const chartsReducer = createReducer(initialState(), { CHARTS_REMOVE: removeChart, CHARTS_SET: setCharts, CHARTS_UPDATE: updateChart, + CHARTS_MOVE_UP: moveUp, }) function addChart(state: ChartsState, action: AddChart) { return state.set('charts', state.get('charts').push(action.chart)) } +function moveUp(state: ChartsState, action: MoveUp) { + const charts = state.get('charts') + const idx = charts.findIndex(chart => chart.topic === action.topic && chart.dotPath === action.dotPath) + const item = charts.get(idx) + const previousItem = charts.get(idx - 1) + + if (idx === 0 || !item || !previousItem) { + return + } + const newlyOrderedCharts = charts.set(idx - 1, item).set(idx, previousItem) + return state.set('charts', newlyOrderedCharts) +} + function updateChart(state: ChartsState, action: UpdateChart) { const charts = state.get('charts') const chartIdx = charts.findIndex(chart => chart.topic === action.topic && chart.dotPath === action.dotPath)