feat(bandChart): add feature flag and update options for Band Chart
parent
894aa99d37
commit
8ce6fe6a17
|
@ -120,6 +120,14 @@
|
|||
contact: Query Team
|
||||
lifetime: temporary
|
||||
|
||||
- name: Band Plot Type
|
||||
description: Enables the creation of a band plot in Dashboards
|
||||
key: bandPlotType
|
||||
default: false
|
||||
contact: Monitoring Team
|
||||
expose: true
|
||||
lifetime: temporary
|
||||
|
||||
- name: Mosaic Graph Type
|
||||
description: Enables the creation of a mosaic graph in Dashboards
|
||||
key: mosaicGraphType
|
||||
|
|
|
@ -212,6 +212,20 @@ func MergedFiltersRule() BoolFlag {
|
|||
return mergeFiltersRule
|
||||
}
|
||||
|
||||
var bandPlotType = MakeBoolFlag(
|
||||
"Band Plot Type",
|
||||
"bandPlotType",
|
||||
"Monitoring Team",
|
||||
false,
|
||||
Temporary,
|
||||
true,
|
||||
)
|
||||
|
||||
// BandPlotType - Enables the creation of a band plot in Dashboards
|
||||
func BandPlotType() BoolFlag {
|
||||
return bandPlotType
|
||||
}
|
||||
|
||||
var mosaicGraphType = MakeBoolFlag(
|
||||
"Mosaic Graph Type",
|
||||
"mosaicGraphType",
|
||||
|
@ -284,6 +298,7 @@ var all = []Flag{
|
|||
simpleTaskOptionsExtraction,
|
||||
useUserPermission,
|
||||
mergeFiltersRule,
|
||||
bandPlotType,
|
||||
mosaicGraphType,
|
||||
notebooks,
|
||||
pushDownGroupAggregateMinMax,
|
||||
|
@ -306,6 +321,7 @@ var byKey = map[string]Flag{
|
|||
"simpleTaskOptionsExtraction": simpleTaskOptionsExtraction,
|
||||
"useUserPermission": useUserPermission,
|
||||
"mergeFiltersRule": mergeFiltersRule,
|
||||
"bandPlotType": bandPlotType,
|
||||
"mosaicGraphType": mosaicGraphType,
|
||||
"notebooks": notebooks,
|
||||
"pushDownGroupAggregateMinMax": pushDownGroupAggregateMinMax,
|
||||
|
|
|
@ -0,0 +1,185 @@
|
|||
// Libraries
|
||||
import React, {FC, useMemo} from 'react'
|
||||
import {Config, Table} from '@influxdata/giraffe'
|
||||
|
||||
// Components
|
||||
import EmptyGraphMessage from 'src/shared/components/EmptyGraphMessage'
|
||||
|
||||
// Utils
|
||||
import {
|
||||
useVisXDomainSettings,
|
||||
useVisYDomainSettings,
|
||||
} from 'src/shared/utils/useVisDomainSettings'
|
||||
import {
|
||||
getFormatter,
|
||||
geomToInterpolation,
|
||||
filterNoisyColumns,
|
||||
parseXBounds,
|
||||
parseYBounds,
|
||||
defaultXColumn,
|
||||
defaultYColumn,
|
||||
} from 'src/shared/utils/vis'
|
||||
|
||||
// Constants
|
||||
import {
|
||||
BAND_LINE_OPACITY,
|
||||
BAND_LINE_WIDTH,
|
||||
BAND_SHADE_OPACITY,
|
||||
VIS_THEME,
|
||||
VIS_THEME_LIGHT,
|
||||
} from 'src/shared/constants'
|
||||
import {DEFAULT_LINE_COLORS} from 'src/shared/constants/graphColorPalettes'
|
||||
import {INVALID_DATA_COPY} from 'src/shared/copy/cell'
|
||||
|
||||
// Types
|
||||
import {BandViewProperties, TimeZone, TimeRange, Theme} from 'src/types'
|
||||
|
||||
interface Props {
|
||||
children: (config: Config) => JSX.Element
|
||||
fluxGroupKeyUnion: string[]
|
||||
timeRange?: TimeRange | null
|
||||
table: Table
|
||||
timeZone: TimeZone
|
||||
viewProperties: BandViewProperties
|
||||
theme: Theme
|
||||
}
|
||||
|
||||
const BandPlot: FC<Props> = ({
|
||||
children,
|
||||
fluxGroupKeyUnion,
|
||||
timeRange,
|
||||
table,
|
||||
timeZone,
|
||||
viewProperties: {
|
||||
geom,
|
||||
colors,
|
||||
xColumn: storedXColumn,
|
||||
yColumn: storedYColumn,
|
||||
upperColumn: upperColumnName,
|
||||
lowerColumn: lowerColumnName,
|
||||
hoverDimension,
|
||||
axes: {
|
||||
x: {
|
||||
label: xAxisLabel,
|
||||
prefix: xTickPrefix,
|
||||
suffix: xTickSuffix,
|
||||
base: xTickBase,
|
||||
bounds: xBounds,
|
||||
},
|
||||
y: {
|
||||
label: yAxisLabel,
|
||||
prefix: yTickPrefix,
|
||||
suffix: yTickSuffix,
|
||||
bounds: yBounds,
|
||||
base: yTickBase,
|
||||
},
|
||||
},
|
||||
timeFormat,
|
||||
},
|
||||
theme,
|
||||
}) => {
|
||||
const storedXDomain = useMemo(() => parseXBounds(xBounds), [xBounds])
|
||||
const storedYDomain = useMemo(() => parseYBounds(yBounds), [yBounds])
|
||||
const xColumn = storedXColumn || defaultXColumn(table, '_time')
|
||||
const yColumn =
|
||||
(table.columnKeys.includes(storedYColumn) && storedYColumn) ||
|
||||
defaultYColumn(table)
|
||||
|
||||
const columnKeys = table.columnKeys
|
||||
|
||||
const isValidView =
|
||||
xColumn &&
|
||||
columnKeys.includes(xColumn) &&
|
||||
yColumn &&
|
||||
columnKeys.includes(yColumn)
|
||||
|
||||
const colorHexes =
|
||||
colors && colors.length
|
||||
? colors.map(c => c.hex)
|
||||
: DEFAULT_LINE_COLORS.map(c => c.hex)
|
||||
|
||||
const interpolation = geomToInterpolation(geom)
|
||||
|
||||
const groupKey = [...fluxGroupKeyUnion, 'result']
|
||||
|
||||
const [xDomain, onSetXDomain, onResetXDomain] = useVisXDomainSettings(
|
||||
storedXDomain,
|
||||
table.getColumn(xColumn, 'number'),
|
||||
timeRange
|
||||
)
|
||||
|
||||
const memoizedYColumnData = useMemo(
|
||||
() => table.getColumn(yColumn, 'number'),
|
||||
[table, yColumn, xColumn, colorHexes, groupKey]
|
||||
)
|
||||
|
||||
const [yDomain, onSetYDomain, onResetYDomain] = useVisYDomainSettings(
|
||||
storedYDomain,
|
||||
memoizedYColumnData
|
||||
)
|
||||
|
||||
const legendColumns = filterNoisyColumns(
|
||||
[...groupKey, xColumn, yColumn],
|
||||
table
|
||||
)
|
||||
|
||||
const xFormatter = getFormatter(table.getColumnType(xColumn), {
|
||||
prefix: xTickPrefix,
|
||||
suffix: xTickSuffix,
|
||||
base: xTickBase,
|
||||
timeZone,
|
||||
timeFormat,
|
||||
})
|
||||
|
||||
const yFormatter = getFormatter(table.getColumnType(yColumn), {
|
||||
prefix: yTickPrefix,
|
||||
suffix: yTickSuffix,
|
||||
base: yTickBase,
|
||||
timeZone,
|
||||
timeFormat,
|
||||
})
|
||||
|
||||
const currentTheme = theme === 'light' ? VIS_THEME_LIGHT : VIS_THEME
|
||||
|
||||
const config: Config = {
|
||||
...currentTheme,
|
||||
table,
|
||||
xAxisLabel,
|
||||
yAxisLabel,
|
||||
xDomain,
|
||||
onSetXDomain,
|
||||
onResetXDomain,
|
||||
yDomain,
|
||||
onSetYDomain,
|
||||
onResetYDomain,
|
||||
legendColumns,
|
||||
valueFormatters: {
|
||||
[xColumn]: xFormatter,
|
||||
[yColumn]: yFormatter,
|
||||
},
|
||||
layers: [
|
||||
{
|
||||
type: 'band',
|
||||
x: xColumn,
|
||||
y: yColumn,
|
||||
fill: groupKey,
|
||||
interpolation,
|
||||
colors: colorHexes,
|
||||
lineWidth: BAND_LINE_WIDTH,
|
||||
lineOpacity: BAND_LINE_OPACITY,
|
||||
shadeOpacity: BAND_SHADE_OPACITY,
|
||||
hoverDimension,
|
||||
upperColumnName,
|
||||
lowerColumnName,
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
if (!isValidView) {
|
||||
return <EmptyGraphMessage message={INVALID_DATA_COPY} />
|
||||
}
|
||||
|
||||
return children(config)
|
||||
}
|
||||
|
||||
export default BandPlot
|
|
@ -14,6 +14,7 @@ import XYPlot from 'src/shared/components/XYPlot'
|
|||
import ScatterPlot from 'src/shared/components/ScatterPlot'
|
||||
import LatestValueTransform from 'src/shared/components/LatestValueTransform'
|
||||
import CheckPlot from 'src/shared/components/CheckPlot'
|
||||
import BandPlot from 'src/shared/components/BandPlot'
|
||||
|
||||
// Types
|
||||
import {
|
||||
|
@ -105,6 +106,19 @@ const ViewSwitcher: FunctionComponent<Props> = ({
|
|||
{config => <Plot config={config} />}
|
||||
</XYPlot>
|
||||
)
|
||||
case 'band':
|
||||
return (
|
||||
<BandPlot
|
||||
timeRange={timeRange}
|
||||
fluxGroupKeyUnion={fluxGroupKeyUnion}
|
||||
table={table}
|
||||
timeZone={timeZone}
|
||||
viewProperties={properties}
|
||||
theme={theme}
|
||||
>
|
||||
{config => <Plot config={config} />}
|
||||
</BandPlot>
|
||||
)
|
||||
|
||||
case 'line-plus-single-stat':
|
||||
const xyProperties = {
|
||||
|
|
|
@ -107,3 +107,7 @@ export const GIRAFFE_COLOR_SCHEMES = [
|
|||
{name: 'Ectoplasm', colors: ECTOPLASM},
|
||||
{name: 'T-MAX 400 Film', colors: T_MAX_400_FILM},
|
||||
]
|
||||
|
||||
export const BAND_LINE_OPACITY = 0.7
|
||||
export const BAND_LINE_WIDTH = 3
|
||||
export const BAND_SHADE_OPACITY = 0.3
|
||||
|
|
|
@ -0,0 +1,250 @@
|
|||
// Libraries
|
||||
import React, {PureComponent} from 'react'
|
||||
import {connect, ConnectedProps} from 'react-redux'
|
||||
|
||||
// Components
|
||||
import {Grid, Form, Dropdown} from '@influxdata/clockface'
|
||||
import Geom from 'src/timeMachine/components/view_options/Geom'
|
||||
import YAxisTitle from 'src/timeMachine/components/view_options/YAxisTitle'
|
||||
import AxisAffixes from 'src/timeMachine/components/view_options/AxisAffixes'
|
||||
import ColorSelector from 'src/timeMachine/components/view_options/ColorSelector'
|
||||
import AutoDomainInput from 'src/shared/components/AutoDomainInput'
|
||||
import YAxisBase from 'src/timeMachine/components/view_options/YAxisBase'
|
||||
import ColumnSelector from 'src/shared/components/ColumnSelector'
|
||||
import Checkbox from 'src/shared/components/Checkbox'
|
||||
import TimeFormat from 'src/timeMachine/components/view_options/TimeFormat'
|
||||
|
||||
// Actions
|
||||
import {
|
||||
setColors,
|
||||
setYAxisLabel,
|
||||
setAxisPrefix,
|
||||
setAxisSuffix,
|
||||
setYAxisBounds,
|
||||
setYAxisBase,
|
||||
setGeom,
|
||||
setXColumn,
|
||||
setYColumn,
|
||||
setShadeBelow,
|
||||
setLinePosition,
|
||||
setTimeFormat,
|
||||
SetHoverDimension,
|
||||
} from 'src/timeMachine/actions'
|
||||
|
||||
// Utils
|
||||
import {parseYBounds} from 'src/shared/utils/vis'
|
||||
import {
|
||||
getXColumnSelection,
|
||||
getYColumnSelection,
|
||||
getNumericColumns,
|
||||
getActiveTimeMachine,
|
||||
} from 'src/timeMachine/selectors'
|
||||
|
||||
// Types
|
||||
import {
|
||||
AppState,
|
||||
XYGeom,
|
||||
Axes,
|
||||
Color,
|
||||
NewView,
|
||||
XYViewProperties,
|
||||
ViewType,
|
||||
} from 'src/types'
|
||||
|
||||
interface OwnProps {
|
||||
type: ViewType
|
||||
axes: Axes
|
||||
geom?: XYGeom
|
||||
colors: Color[]
|
||||
shadeBelow?: boolean
|
||||
hoverDimension?: 'auto' | 'x' | 'y' | 'xy'
|
||||
}
|
||||
|
||||
type ReduxProps = ConnectedProps<typeof connector>
|
||||
type Props = OwnProps & ReduxProps
|
||||
|
||||
class BandOptions extends PureComponent<Props> {
|
||||
public render() {
|
||||
const {
|
||||
axes: {
|
||||
y: {label, prefix, suffix, base},
|
||||
},
|
||||
colors,
|
||||
geom,
|
||||
shadeBelow,
|
||||
onUpdateColors,
|
||||
onUpdateYAxisLabel,
|
||||
onUpdateAxisPrefix,
|
||||
onUpdateAxisSuffix,
|
||||
onUpdateYAxisBase,
|
||||
onSetShadeBelow,
|
||||
onSetGeom,
|
||||
onSetYColumn,
|
||||
yColumn,
|
||||
onSetXColumn,
|
||||
xColumn,
|
||||
numericColumns,
|
||||
onSetTimeFormat,
|
||||
timeFormat,
|
||||
hoverDimension = 'auto',
|
||||
onSetHoverDimension,
|
||||
} = this.props
|
||||
|
||||
return (
|
||||
<>
|
||||
<Grid.Column>
|
||||
<h4 className="view-options--header">Customize Band Plot</h4>
|
||||
<h5 className="view-options--header">Data</h5>
|
||||
<ColumnSelector
|
||||
selectedColumn={xColumn}
|
||||
onSelectColumn={onSetXColumn}
|
||||
availableColumns={numericColumns}
|
||||
axisName="x"
|
||||
/>
|
||||
<ColumnSelector
|
||||
selectedColumn={yColumn}
|
||||
onSelectColumn={onSetYColumn}
|
||||
availableColumns={numericColumns}
|
||||
axisName="y"
|
||||
/>
|
||||
<Form.Element label="Time Format">
|
||||
<TimeFormat
|
||||
timeFormat={timeFormat}
|
||||
onTimeFormatChange={onSetTimeFormat}
|
||||
/>
|
||||
</Form.Element>
|
||||
<h5 className="view-options--header">Options</h5>
|
||||
</Grid.Column>
|
||||
{geom && <Geom geom={geom} onSetGeom={onSetGeom} />}
|
||||
<ColorSelector
|
||||
colors={colors.filter(c => c.type === 'scale')}
|
||||
onUpdateColors={onUpdateColors}
|
||||
/>
|
||||
<Grid.Column>
|
||||
<Checkbox
|
||||
label="Shade Area Below Lines"
|
||||
checked={!!shadeBelow}
|
||||
onSetChecked={onSetShadeBelow}
|
||||
/>
|
||||
</Grid.Column>
|
||||
<Grid.Column>
|
||||
<br />
|
||||
<Form.Element label="Hover Dimension">
|
||||
<Dropdown
|
||||
button={(active, onClick) => (
|
||||
<Dropdown.Button active={active} onClick={onClick}>
|
||||
{hoverDimension}
|
||||
</Dropdown.Button>
|
||||
)}
|
||||
menu={onCollapse => (
|
||||
<Dropdown.Menu onCollapse={onCollapse}>
|
||||
<Dropdown.Item
|
||||
id="auto"
|
||||
value="auto"
|
||||
onClick={onSetHoverDimension}
|
||||
selected={hoverDimension === 'auto'}
|
||||
>
|
||||
Auto
|
||||
</Dropdown.Item>
|
||||
<Dropdown.Item
|
||||
id="x"
|
||||
value="x"
|
||||
onClick={onSetHoverDimension}
|
||||
selected={hoverDimension === 'x'}
|
||||
>
|
||||
X Axis
|
||||
</Dropdown.Item>
|
||||
<Dropdown.Item
|
||||
id="y"
|
||||
value="y"
|
||||
onClick={onSetHoverDimension}
|
||||
selected={hoverDimension === 'y'}
|
||||
>
|
||||
Y Axis
|
||||
</Dropdown.Item>
|
||||
<Dropdown.Item
|
||||
id="xy"
|
||||
value="xy"
|
||||
onClick={onSetHoverDimension}
|
||||
selected={hoverDimension === 'xy'}
|
||||
>
|
||||
X & Y Axis
|
||||
</Dropdown.Item>
|
||||
</Dropdown.Menu>
|
||||
)}
|
||||
/>
|
||||
</Form.Element>
|
||||
</Grid.Column>
|
||||
<Grid.Column>
|
||||
<h5 className="view-options--header">Y Axis</h5>
|
||||
</Grid.Column>
|
||||
<YAxisTitle label={label} onUpdateYAxisLabel={onUpdateYAxisLabel} />
|
||||
<YAxisBase base={base} onUpdateYAxisBase={onUpdateYAxisBase} />
|
||||
<AxisAffixes
|
||||
prefix={prefix}
|
||||
suffix={suffix}
|
||||
axisName="y"
|
||||
onUpdateAxisPrefix={prefix => onUpdateAxisPrefix(prefix, 'y')}
|
||||
onUpdateAxisSuffix={suffix => onUpdateAxisSuffix(suffix, 'y')}
|
||||
/>
|
||||
<Grid.Column>
|
||||
<AutoDomainInput
|
||||
domain={this.yDomain}
|
||||
onSetDomain={this.handleSetYDomain}
|
||||
label="Y Axis Domain"
|
||||
/>
|
||||
</Grid.Column>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
private get yDomain(): [number, number] {
|
||||
return parseYBounds(this.props.axes.y.bounds)
|
||||
}
|
||||
|
||||
private setBoundValues = (value: number | null): string | null => {
|
||||
return value === null ? null : String(value)
|
||||
}
|
||||
|
||||
private handleSetYDomain = (yDomain: [number, number]): void => {
|
||||
let bounds: [string | null, string | null]
|
||||
|
||||
if (yDomain) {
|
||||
const [min, max] = yDomain
|
||||
bounds = [this.setBoundValues(min), this.setBoundValues(max)]
|
||||
} else {
|
||||
bounds = [null, null]
|
||||
}
|
||||
|
||||
this.props.onUpdateYAxisBounds(bounds)
|
||||
}
|
||||
}
|
||||
|
||||
const mstp = (state: AppState) => {
|
||||
const xColumn = getXColumnSelection(state)
|
||||
const yColumn = getYColumnSelection(state)
|
||||
const numericColumns = getNumericColumns(state)
|
||||
const view = getActiveTimeMachine(state).view as NewView<XYViewProperties>
|
||||
const {timeFormat} = view.properties
|
||||
return {xColumn, yColumn, numericColumns, timeFormat}
|
||||
}
|
||||
|
||||
const mdtp = {
|
||||
onUpdateYAxisLabel: setYAxisLabel,
|
||||
onUpdateAxisPrefix: setAxisPrefix,
|
||||
onUpdateAxisSuffix: setAxisSuffix,
|
||||
onUpdateYAxisBounds: setYAxisBounds,
|
||||
onUpdateYAxisBase: setYAxisBase,
|
||||
onSetXColumn: setXColumn,
|
||||
onSetYColumn: setYColumn,
|
||||
onSetShadeBelow: setShadeBelow,
|
||||
onUpdateColors: setColors,
|
||||
onSetGeom: setGeom,
|
||||
onSetPosition: setLinePosition,
|
||||
onSetTimeFormat: setTimeFormat,
|
||||
onSetHoverDimension: SetHoverDimension,
|
||||
}
|
||||
|
||||
const connector = connect(mstp, mdtp)
|
||||
|
||||
export default connector(BandOptions)
|
|
@ -2,6 +2,7 @@
|
|||
import React, {PureComponent} from 'react'
|
||||
|
||||
// Components
|
||||
import BandOptions from 'src/timeMachine/components/view_options/BandOptions'
|
||||
import LineOptions from 'src/timeMachine/components/view_options/LineOptions'
|
||||
import GaugeOptions from 'src/timeMachine/components/view_options/GaugeOptions'
|
||||
import SingleStatOptions from 'src/timeMachine/components/view_options/SingleStatOptions'
|
||||
|
@ -32,6 +33,8 @@ class OptionsSwitcher extends PureComponent<Props> {
|
|||
)
|
||||
case 'xy':
|
||||
return <LineOptions {...view.properties} />
|
||||
case 'band':
|
||||
return <BandOptions {...view.properties} />
|
||||
case 'gauge':
|
||||
return <GaugeOptions {...view.properties} />
|
||||
case 'single-stat':
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
@import "src/style/modules";
|
||||
@import 'src/style/modules';
|
||||
|
||||
.view-type-dropdown {
|
||||
.cf-dropdown-item--children, .cf-dropdown--selected {
|
||||
.cf-dropdown-item--children,
|
||||
.cf-dropdown--selected {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
@ -50,6 +51,11 @@
|
|||
stroke: $g13-mist;
|
||||
}
|
||||
|
||||
.vis-graphic--line-e {
|
||||
stroke: $c-honeydew;
|
||||
stroke-width: 4px;
|
||||
}
|
||||
|
||||
.vis-graphic--fill-a {
|
||||
fill: $g11-sidewalk;
|
||||
}
|
||||
|
@ -95,6 +101,11 @@
|
|||
fill: $c-honeydew;
|
||||
}
|
||||
|
||||
.vis-graphic--fill-e {
|
||||
fill: $c-honeydew;
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
.vis-graphic--fill-a,
|
||||
.vis-graphic--fill-b,
|
||||
.vis-graphic--fill-c {
|
||||
|
|
|
@ -58,6 +58,9 @@ class ViewTypeDropdown extends PureComponent<Props> {
|
|||
if (g.type === 'mosaic' && !isFlagEnabled('mosaicGraphType')) {
|
||||
return false
|
||||
}
|
||||
if (g.type === 'band' && !isFlagEnabled('bandPlotType')) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}).map(g => {
|
||||
return (
|
||||
|
|
|
@ -6,6 +6,10 @@ interface VisType {
|
|||
}
|
||||
|
||||
export const VIS_TYPES: VisType[] = [
|
||||
{
|
||||
type: 'band',
|
||||
name: 'Band Plot',
|
||||
},
|
||||
{
|
||||
type: 'xy',
|
||||
name: 'Graph',
|
||||
|
|
|
@ -470,6 +470,37 @@ const GRAPHIC_SVGS = {
|
|||
</svg>
|
||||
</div>
|
||||
),
|
||||
band: (
|
||||
<div className="vis-graphic" data-testid="vis-graphic--band-chart">
|
||||
<svg
|
||||
id="Band Chart"
|
||||
x="0px"
|
||||
y="0px"
|
||||
width="100%"
|
||||
height="100%"
|
||||
viewBox="0 0 150 150"
|
||||
>
|
||||
<path
|
||||
className="vis-graphic--fill vis-graphic--fill-e"
|
||||
d="M10,127V52.6v-8c0-1.8,0.8-3.5,2.2-4.6l25-18.3c1.6-1.2,3.7-0.9,5,0.5l24.6,26.9c1.8,1.9,4.5,2.1,6.5,0.5
|
||||
L104,23c1.8-1.5,7.1-1.5,8.3,0.6l16.5,27c0.7,1.2,2,1.9,3.3,1.9h7.9v5.5V127H10z"
|
||||
/>
|
||||
<path
|
||||
className="vis-graphic--line vis-graphic--line-c"
|
||||
d="M39.5,22c0.8,0,1.5,0.3,2.1,1l24.6,26.9c1.1,1.2,2.7,1.9,4.3,1.9c1.3,0,2.6-0.5,3.7-1.3l30.5-26.7
|
||||
c0.6-0.5,1.9-0.8,3.3-0.8c1.7,0,3.1,0.5,3.5,1.2l16.5,27c0.9,1.5,2.5,2.4,4.2,2.4h6.9v4.5V126H11V52.6v-8c0-1.5,0.7-2.9,1.8-3.7
|
||||
l25-18.3C38.3,22.2,38.9,22,39.5,22 M39.5,21c-0.8,0-1.5,0.2-2.2,0.7L12.2,40c-1.4,1-2.2,2.7-2.2,4.6v8V127h130V58.1v-5.5h-7.9
|
||||
c-1.3,0-2.6-0.7-3.3-1.9l-16.5-27c-0.7-1.1-2.5-1.7-4.4-1.7c-1.6,0-3.1,0.4-4,1.1L73.5,49.7c-0.9,0.7-1.9,1.1-3,1.1
|
||||
c-1.3,0-2.6-0.5-3.5-1.6L42.3,22.3C41.5,21.4,40.5,21,39.5,21L39.5,21z"
|
||||
/>
|
||||
<path
|
||||
className="vis-graphic--line vis-graphic--line-e"
|
||||
d="M10,91h0.2c1.2,0,2.4-0.4,3.3-1.2L35.6,71c2-1.7,5-1.6,6.9,0.3L66.6,96c2.1,2.1,5.6,2,7.5-0.3l29.2-34.4
|
||||
c2.2-2.6,6.4-2.3,8.2,0.6l15,24.6c0.9,1.5,2.5,2.4,4.3,2.4h9.3"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
),
|
||||
xy: (
|
||||
<div className="vis-graphic" data-testid="vis-graphic--xy">
|
||||
<svg
|
||||
|
|
|
@ -474,6 +474,7 @@ export const timeMachineReducer = (
|
|||
return setViewProperties(state, {prefix})
|
||||
case 'check':
|
||||
case 'xy':
|
||||
case 'band':
|
||||
return setYAxis(state, {prefix})
|
||||
default:
|
||||
return state
|
||||
|
@ -490,6 +491,7 @@ export const timeMachineReducer = (
|
|||
return setViewProperties(state, {tickPrefix})
|
||||
case 'check':
|
||||
case 'xy':
|
||||
case 'band':
|
||||
return setYAxis(state, {tickPrefix})
|
||||
default:
|
||||
return state
|
||||
|
@ -506,6 +508,7 @@ export const timeMachineReducer = (
|
|||
return setViewProperties(state, {suffix})
|
||||
case 'check':
|
||||
case 'xy':
|
||||
case 'band':
|
||||
return setYAxis(state, {suffix})
|
||||
default:
|
||||
return state
|
||||
|
@ -522,6 +525,7 @@ export const timeMachineReducer = (
|
|||
return setViewProperties(state, {tickSuffix})
|
||||
case 'check':
|
||||
case 'xy':
|
||||
case 'band':
|
||||
return setYAxis(state, {tickSuffix})
|
||||
default:
|
||||
return state
|
||||
|
@ -538,6 +542,7 @@ export const timeMachineReducer = (
|
|||
case 'scatter':
|
||||
case 'check':
|
||||
case 'xy':
|
||||
case 'band':
|
||||
case 'histogram':
|
||||
return setViewProperties(state, {colors})
|
||||
case 'line-plus-single-stat':
|
||||
|
|
|
@ -355,6 +355,17 @@ export const getSaveableView = (state: AppState): QueryView & {id?: string} => {
|
|||
}
|
||||
}
|
||||
|
||||
if (saveableView.properties.type === 'band') {
|
||||
saveableView = {
|
||||
...saveableView,
|
||||
properties: {
|
||||
...saveableView.properties,
|
||||
xColumn: getXColumnSelection(state),
|
||||
yColumn: getYColumnSelection(state),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if (saveableView.properties.type === 'line-plus-single-stat') {
|
||||
saveableView = {
|
||||
...saveableView,
|
||||
|
|
Loading…
Reference in New Issue