From d56881b82f5fa480830f3dcb4d22645337f9008d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Benitte?= Date: Fri, 3 May 2019 05:47:42 +0900 Subject: [PATCH] feat(line): fix slices spacing & add support for y axis --- packages/line/index.d.ts | 12 +- packages/line/src/{LineAreas.js => Areas.js} | 8 +- packages/line/src/Line.js | 103 +++++---- packages/line/src/LineCanvas.js | 7 +- packages/line/src/LinePoints.js | 118 ---------- packages/line/src/LineSlices.js | 66 ------ packages/line/src/LineSlicesItem.js | 98 -------- packages/line/src/{LineLines.js => Lines.js} | 34 ++- .../line/src/{LineLine.js => LinesItem.js} | 8 +- packages/line/src/{LineMesh.js => Mesh.js} | 12 +- .../{LinePointTooltip.js => PointTooltip.js} | 0 packages/line/src/Points.js | 115 ++++++++++ ...{LineStackedTooltip.js => SliceTooltip.js} | 20 +- packages/line/src/Slices.js | 50 ++++ packages/line/src/SlicesItem.js | 64 ++++++ packages/line/src/hooks.js | 217 +++++++++++++----- packages/line/src/props.js | 22 +- packages/line/stories/line.stories.js | 19 +- packages/tooltip/index.d.ts | 13 ++ packages/tooltip/src/components/Crosshair.js | 4 + packages/tooltip/src/props.js | 4 +- .../src/components/controls/ChoicesControl.js | 2 +- website/src/components/controls/Switch.js | 5 +- website/src/data/components/line/defaults.js | 3 +- website/src/data/components/line/meta.yml | 2 + website/src/data/components/line/props.js | 40 +++- website/src/data/nav.js | 96 ++++---- website/src/pages/bar/index.js | 25 +- website/src/pages/line/api.js | 8 +- website/src/pages/line/index.js | 2 +- 30 files changed, 639 insertions(+), 538 deletions(-) rename packages/line/src/{LineAreas.js => Areas.js} (93%) delete mode 100644 packages/line/src/LinePoints.js delete mode 100644 packages/line/src/LineSlices.js delete mode 100644 packages/line/src/LineSlicesItem.js rename packages/line/src/{LineLines.js => Lines.js} (73%) rename packages/line/src/{LineLine.js => LinesItem.js} (91%) rename packages/line/src/{LineMesh.js => Mesh.js} (93%) rename packages/line/src/{LinePointTooltip.js => PointTooltip.js} (100%) create mode 100644 packages/line/src/Points.js rename packages/line/src/{LineStackedTooltip.js => SliceTooltip.js} (57%) create mode 100644 packages/line/src/Slices.js create mode 100644 packages/line/src/SlicesItem.js diff --git a/packages/line/index.d.ts b/packages/line/index.d.ts index a91eea96c..a8ddba7af 100644 --- a/packages/line/index.d.ts +++ b/packages/line/index.d.ts @@ -12,6 +12,7 @@ import { OrdinalColorsInstruction } from '@nivo/colors' import { LegendProps } from '@nivo/legends' import { Scale, ScaleFunc } from '@nivo/scales' import { AxisProps } from '@nivo/axes' +import { CrosshairType } from '@nivo/tooltip' type Omit = Pick> @@ -128,11 +129,18 @@ declare module '@nivo/line' { markers?: CartesianMarkerProps[] isInteractive?: boolean + debugMesh?: boolean - enableStackTooltip?: boolean - tooltip?: (data: LineSliceData) => React.ReactNode + + enableSlices?: 'x' | 'y' | false + debugSlices?: boolean + sliceTooltip?: (data: LineSliceData) => React.ReactNode + tooltipFormat?: TooltipFormatter | string + enableCrosshair?: boolean + crosshairType?: CrosshairType + legends?: LegendProps[] } diff --git a/packages/line/src/LineAreas.js b/packages/line/src/Areas.js similarity index 93% rename from packages/line/src/LineAreas.js rename to packages/line/src/Areas.js index c6c7c134e..fabf2968b 100644 --- a/packages/line/src/LineAreas.js +++ b/packages/line/src/Areas.js @@ -10,7 +10,7 @@ import React, { memo } from 'react' import PropTypes from 'prop-types' import { useMotionConfig, SmartMotion, blendModePropType } from '@nivo/core' -const LineAreas = memo(({ areaGenerator, areaOpacity, areaBlendMode, lines }) => { +const Areas = memo(({ areaGenerator, areaOpacity, areaBlendMode, lines }) => { const { animate, springConfig } = useMotionConfig() if (animate !== true) { @@ -64,10 +64,10 @@ const LineAreas = memo(({ areaGenerator, areaOpacity, areaBlendMode, lines }) => ) }) -LineAreas.displayName = 'LineAreas' -LineAreas.propTypes = { +Areas.displayName = 'Areas' +Areas.propTypes = { areaOpacity: PropTypes.number.isRequired, areaBlendMode: blendModePropType.isRequired, } -export default LineAreas +export default Areas diff --git a/packages/line/src/Line.js b/packages/line/src/Line.js index bf2752c52..4dce6cfd0 100644 --- a/packages/line/src/Line.js +++ b/packages/line/src/Line.js @@ -12,13 +12,13 @@ import { useInheritedColor } from '@nivo/colors' import { Axes, Grid } from '@nivo/axes' import { BoxLegendSvg } from '@nivo/legends' import { Crosshair } from '@nivo/tooltip' -import { useLine, useLinePoints } from './hooks' +import { useLine } from './hooks' import { LinePropTypes, LineDefaultProps } from './props' -import LineAreas from './LineAreas' -import LineLines from './LineLines' -import LineSlices from './LineSlices' -import LinePoints from './LinePoints' -import LineMesh from './LineMesh' +import Areas from './Areas' +import Lines from './Lines' +import Slices from './Slices' +import Points from './Points' +import Mesh from './Mesh' const Line = props => { const { @@ -67,16 +67,20 @@ const Line = props => { legends, isInteractive, + useMesh, debugMesh, + onMouseEnter, onMouseMove, onMouseLeave, onClick, + tooltip, - tooltipFormat, - enableStackTooltip, - stackTooltip, + + enableSlices, + debugSlices, + sliceTooltip, enableCrosshair, crosshairType, @@ -88,26 +92,20 @@ const Line = props => { partialMargin ) - const { lineGenerator, areaGenerator, series, xScale, yScale, slices } = useLine({ + const { lineGenerator, areaGenerator, series, xScale, yScale, slices, points } = useLine({ data, xScale: xScaleSpec, + xFormat, yScale: yScaleSpec, + yFormat, width: innerWidth, height: innerHeight, colors, curve, areaBaselineValue, - }) - - const points = useLinePoints({ - isEnabled: - enablePoints === true || - (isInteractive === true && useMesh === true && enableStackTooltip !== true), - series, - xFormat, - yFormat, - color: pointColor, - borderColor: pointBorderColor, + pointColor, + pointBorderColor, + enableSlices, }) const theme = useTheme() @@ -115,6 +113,7 @@ const Line = props => { const getPointBorderColor = useInheritedColor(pointBorderColor, theme) const [currentPoint, setCurrentPoint] = useState(null) + const [currentSlice, setCurrentSlice] = useState(null) const legendData = series .map(line => ({ @@ -164,12 +163,7 @@ const Line = props => { ), areas: null, lines: ( - + ), slices: null, points: null, @@ -189,7 +183,7 @@ const Line = props => { if (enableArea) { layerById.areas = ( - { ) } - if (isInteractive && enableStackTooltip) { + if (isInteractive && enableSlices !== false) { layerById.slices = ( - ) } if (enablePoints) { layerById.points = ( - { ) } - if (isInteractive && enableCrosshair && currentPoint) { - layerById.crosshair = ( - - ) + if (isInteractive && enableCrosshair) { + if (currentPoint !== null) { + layerById.crosshair = ( + + ) + } + if (currentSlice !== null) { + layerById.crosshair = ( + + ) + } } - if (isInteractive && useMesh && !enableStackTooltip) { + if (isInteractive && useMesh && enableSlices === false) { layerById.mesh = ( - { - const theme = useTheme() - const { animate, springConfig } = useMotionConfig() - const getLabel = getLabelGenerator(label) - - const mappedPoints = points.map(point => { - const mappedPoint = { - id: point.id, - x: point.x, - y: point.y, - datum: point.data, - fill: point.color, - stroke: point.borderColor, - label: enableLabel ? getLabel(point.data) : null, - } - - return mappedPoint - }) - - if (animate !== true) { - return ( - - {mappedPoints.map(point => ( - - ))} - - ) - } - - return ( - { - return { - key: point.id, - data: point, - style: { - x: spring(point.x, springConfig), - y: spring(point.y, springConfig), - size: spring(size, springConfig), - }, - } - })} - > - {interpolatedStyles => ( - - {interpolatedStyles.map(({ key, style, data: point }) => ( - - ))} - - )} - - ) - } -) - -LinePoints.displayName = 'LinePoints' -LinePoints.propTypes = { - lines: PropTypes.arrayOf( - PropTypes.shape({ - id: PropTypes.string.isRequired, - }) - ), - - symbol: PropTypes.func, - size: PropTypes.number.isRequired, - color: PropTypes.func.isRequired, - borderWidth: PropTypes.number.isRequired, - borderColor: PropTypes.func.isRequired, - - enableLabel: PropTypes.bool.isRequired, - label: PropTypes.oneOfType([PropTypes.string, PropTypes.func]).isRequired, - labelYOffset: PropTypes.number, -} - -LinePoints.defaultProps = { - enableLabel: false, - label: 'yFormatted', -} - -export default LinePoints diff --git a/packages/line/src/LineSlices.js b/packages/line/src/LineSlices.js deleted file mode 100644 index daca67425..000000000 --- a/packages/line/src/LineSlices.js +++ /dev/null @@ -1,66 +0,0 @@ -/* - * This file is part of the nivo project. - * - * Copyright 2016-present, Raphaël Benitte. - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -import React, { memo } from 'react' -import PropTypes from 'prop-types' -import LineSlicesItem from './LineSlicesItem' - -const LineSlices = memo(({ slices, height, tooltip, tooltipFormat }) => { - return slices.map(slice => ( - - )) -}) - -LineSlices.displayName = 'LineSlices' -LineSlices.propTypes = { - slices: PropTypes.arrayOf( - PropTypes.shape({ - id: PropTypes.oneOfType([ - PropTypes.number, - PropTypes.string, - PropTypes.instanceOf(Date), - ]).isRequired, - x: PropTypes.number.isRequired, - data: PropTypes.arrayOf( - PropTypes.shape({ - data: PropTypes.shape({ - x: PropTypes.oneOfType([ - PropTypes.number, - PropTypes.string, - PropTypes.instanceOf(Date), - ]), - y: PropTypes.oneOfType([ - PropTypes.number, - PropTypes.string, - PropTypes.instanceOf(Date), - ]), - }), - position: PropTypes.shape({ - x: PropTypes.number, - y: PropTypes.number, - }).isRequired, - serie: PropTypes.shape({ - id: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired, - color: PropTypes.string.isRequired, - }).isRequired, - }) - ).isRequired, - }) - ).isRequired, - height: PropTypes.number.isRequired, - tooltip: PropTypes.oneOfType([PropTypes.func, PropTypes.object]).isRequired, - tooltipFormat: PropTypes.oneOfType([PropTypes.func, PropTypes.string]), -} - -export default LineSlices diff --git a/packages/line/src/LineSlicesItem.js b/packages/line/src/LineSlicesItem.js deleted file mode 100644 index 4fe6120ad..000000000 --- a/packages/line/src/LineSlicesItem.js +++ /dev/null @@ -1,98 +0,0 @@ -/* - * This file is part of the nivo project. - * - * Copyright 2016-present, Raphaël Benitte. - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -import React, { useState, useCallback } from 'react' -import PropTypes from 'prop-types' -import { useTheme, useValueFormatter } from '@nivo/core' -import { TableTooltip, useTooltip } from '@nivo/tooltip' - -const Chip = ({ color }) => ( - -) - -Chip.propTypes = { - color: PropTypes.string.isRequired, -} - -const SliceTooltip = ({ slice, formatValue }) => { - return ( - d.position.x !== null && d.position.y !== null) - .map(d => [, d.serie.id, formatValue(d.data.y)])} - /> - ) -} - -const LineSlicesItem = ({ slice, height, tooltip, tooltipFormat }) => { - const theme = useTheme() - const formatValue = useValueFormatter(tooltipFormat) - const { showTooltipFromEvent, hideTooltip } = useTooltip() - const [isHover, setIsHover] = useState(false) - const hasValues = slice.data.some(d => d.position.x !== null && d.position.y !== null) - - const handleMouseEnter = useCallback( - event => { - showTooltipFromEvent( - React.createElement(tooltip, { slice, formatValue }), - event, - 'right' - ) - setIsHover(true) - }, - [showTooltipFromEvent, tooltip, slice, formatValue] - ) - - const handleMouseMove = useCallback( - event => { - showTooltipFromEvent( - React.createElement(tooltip, { slice, formatValue }), - event, - 'right' - ) - }, - [showTooltipFromEvent, tooltip, slice, formatValue] - ) - - const handleMouseLeave = useCallback(() => { - hideTooltip() - setIsHover(false) - }, [hideTooltip]) - - if (!hasValues) return null - - return ( - - {isHover && ( - - )} - - - ) -} - -LineSlicesItem.propTypes = { - slice: PropTypes.object.isRequired, - height: PropTypes.number.isRequired, - tooltip: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), - tooltipFormat: PropTypes.oneOfType([PropTypes.func, PropTypes.string]), -} -LineSlicesItem.defaultProps = { - tooltip: SliceTooltip, -} - -export default LineSlicesItem diff --git a/packages/line/src/LineLines.js b/packages/line/src/Lines.js similarity index 73% rename from packages/line/src/LineLines.js rename to packages/line/src/Lines.js index 65ffcd838..874d03ae2 100644 --- a/packages/line/src/LineLines.js +++ b/packages/line/src/Lines.js @@ -8,25 +8,23 @@ */ import React, { memo } from 'react' import PropTypes from 'prop-types' -import Line from './LineLine' +import LinesItem from './LinesItem' -const LineLines = memo(({ lines, lineGenerator, lineWidth }) => ( - <> - {lines.map(({ id, data, color }) => ( - d.position)} - lineGenerator={lineGenerator} - color={color} - thickness={lineWidth} - /> - ))} - -)) +const Lines = memo(({ lines, lineGenerator, lineWidth }) => { + return lines.map(({ id, data, color }) => ( + d.position)} + lineGenerator={lineGenerator} + color={color} + thickness={lineWidth} + /> + )) +}) -LineLines.displayName = 'LineLines' -LineLines.propTypes = { +Lines.displayName = 'Lines' +Lines.propTypes = { lines: PropTypes.arrayOf( PropTypes.shape({ id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired, @@ -57,4 +55,4 @@ LineLines.propTypes = { lineGenerator: PropTypes.func.isRequired, } -export default LineLines +export default Lines diff --git a/packages/line/src/LineLine.js b/packages/line/src/LinesItem.js similarity index 91% rename from packages/line/src/LineLine.js rename to packages/line/src/LinesItem.js index 113c66423..ee6d8d848 100644 --- a/packages/line/src/LineLine.js +++ b/packages/line/src/LinesItem.js @@ -11,7 +11,7 @@ import PropTypes from 'prop-types' import { useMotionConfig } from '@nivo/core' import { SmartMotion } from '@nivo/core' -const LineLine = memo(({ lineGenerator, id, points, color, thickness }) => { +const LinesItem = memo(({ lineGenerator, id, points, color, thickness }) => { const { animate, springConfig } = useMotionConfig() if (animate !== true) { @@ -47,8 +47,8 @@ const LineLine = memo(({ lineGenerator, id, points, color, thickness }) => { ) }) -LineLine.displayName = 'LineLine' -LineLine.propTypes = { +LinesItem.displayName = 'LinesItem' +LinesItem.propTypes = { id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired, points: PropTypes.arrayOf( PropTypes.shape({ @@ -61,4 +61,4 @@ LineLine.propTypes = { thickness: PropTypes.number.isRequired, } -export default LineLine +export default LinesItem diff --git a/packages/line/src/LineMesh.js b/packages/line/src/Mesh.js similarity index 93% rename from packages/line/src/LineMesh.js rename to packages/line/src/Mesh.js index 88ec1b26f..397a297f3 100644 --- a/packages/line/src/LineMesh.js +++ b/packages/line/src/Mesh.js @@ -9,9 +9,9 @@ import React, { memo, useCallback } from 'react' import PropTypes from 'prop-types' import { useTooltip } from '@nivo/tooltip' -import { Mesh } from '@nivo/voronoi' +import { Mesh as BaseMesh } from '@nivo/voronoi' -const LineMesh = memo( +const Mesh = memo( ({ points, width, @@ -66,7 +66,7 @@ const LineMesh = memo( ) return ( - { + const theme = useTheme() + const { animate, springConfig } = useMotionConfig() + const getLabel = getLabelGenerator(label) + + const mappedPoints = points.map(point => { + const mappedPoint = { + id: point.id, + x: point.x, + y: point.y, + datum: point.data, + fill: point.color, + stroke: point.borderColor, + label: enableLabel ? getLabel(point.data) : null, + } + + return mappedPoint + }) + + if (animate !== true) { + return ( + + {mappedPoints.map(point => ( + + ))} + + ) + } + + return ( + { + return { + key: point.id, + data: point, + style: { + x: spring(point.x, springConfig), + y: spring(point.y, springConfig), + size: spring(size, springConfig), + }, + } + })} + > + {interpolatedStyles => ( + + {interpolatedStyles.map(({ key, style, data: point }) => ( + + ))} + + )} + + ) +}) + +Points.displayName = 'Points' +Points.propTypes = { + lines: PropTypes.arrayOf( + PropTypes.shape({ + id: PropTypes.string.isRequired, + }) + ), + + symbol: PropTypes.func, + size: PropTypes.number.isRequired, + color: PropTypes.func.isRequired, + borderWidth: PropTypes.number.isRequired, + borderColor: PropTypes.func.isRequired, + + enableLabel: PropTypes.bool.isRequired, + label: PropTypes.oneOfType([PropTypes.string, PropTypes.func]).isRequired, + labelYOffset: PropTypes.number, +} +Points.defaultProps = { + enableLabel: false, + label: 'yFormatted', +} + +export default Points diff --git a/packages/line/src/LineStackedTooltip.js b/packages/line/src/SliceTooltip.js similarity index 57% rename from packages/line/src/LineStackedTooltip.js rename to packages/line/src/SliceTooltip.js index 3c1e76f27..004f78e1d 100644 --- a/packages/line/src/LineStackedTooltip.js +++ b/packages/line/src/SliceTooltip.js @@ -18,20 +18,24 @@ Chip.propTypes = { color: PropTypes.string.isRequired, } -const LineStackedTooltip = memo(({ slice, formatValue }) => { +const SliceTooltip = memo(({ slice, axis }) => { + const otherAxis = axis === 'x' ? 'y' : 'x' + return ( d.position.x !== null && d.position.y !== null) - .map(d => [, d.serie.id, formatValue(d.data.y)])} + rows={slice.points.map(point => [ + , + point.serieId, + {point.data[`${otherAxis}Formatted`]}, + ])} /> ) }) -LineStackedTooltip.displayName = 'LineStackedTooltip' -LineStackedTooltip.propTypes = { +SliceTooltip.displayName = 'SliceTooltip' +SliceTooltip.propTypes = { slice: PropTypes.object.isRequired, - formatValue: PropTypes.func.isRequired, + axis: PropTypes.oneOf(['x', 'y']).isRequired, } -export default LineStackedTooltip +export default SliceTooltip diff --git a/packages/line/src/Slices.js b/packages/line/src/Slices.js new file mode 100644 index 000000000..66bcfcbad --- /dev/null +++ b/packages/line/src/Slices.js @@ -0,0 +1,50 @@ +/* + * This file is part of the nivo project. + * + * Copyright 2016-present, Raphaël Benitte. + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +import React, { memo } from 'react' +import PropTypes from 'prop-types' +import SlicesItem from './SlicesItem' + +const Slices = memo(({ slices, axis, debug, height, tooltip, current, setCurrent }) => { + return slices.map(slice => ( + + )) +}) + +Slices.displayName = 'Slices' +Slices.propTypes = { + slices: PropTypes.arrayOf( + PropTypes.shape({ + id: PropTypes.oneOfType([ + PropTypes.number, + PropTypes.string, + PropTypes.instanceOf(Date), + ]).isRequired, + x: PropTypes.number.isRequired, + y: PropTypes.number.isRequired, + points: PropTypes.arrayOf(PropTypes.object).isRequired, + }) + ).isRequired, + axis: PropTypes.oneOf(['x', 'y']).isRequired, + debug: PropTypes.bool.isRequired, + height: PropTypes.number.isRequired, + tooltip: PropTypes.oneOfType([PropTypes.func, PropTypes.object]).isRequired, + current: PropTypes.object, + setCurrent: PropTypes.func.isRequired, +} + +export default Slices diff --git a/packages/line/src/SlicesItem.js b/packages/line/src/SlicesItem.js new file mode 100644 index 000000000..1aa52bc9d --- /dev/null +++ b/packages/line/src/SlicesItem.js @@ -0,0 +1,64 @@ +/* + * This file is part of the nivo project. + * + * Copyright 2016-present, Raphaël Benitte. + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +import React, { memo, useCallback } from 'react' +import PropTypes from 'prop-types' +import { useTooltip } from '@nivo/tooltip' + +const SlicesItem = memo(({ slice, axis, debug, tooltip, isCurrent, setCurrent }) => { + const { showTooltipFromEvent, hideTooltip } = useTooltip() + + const handleMouseEnter = useCallback( + event => { + showTooltipFromEvent(React.createElement(tooltip, { slice, axis }), event, 'right') + setCurrent(slice) + }, + [showTooltipFromEvent, tooltip, slice] + ) + + const handleMouseMove = useCallback( + event => { + showTooltipFromEvent(React.createElement(tooltip, { slice, axis }), event, 'right') + }, + [showTooltipFromEvent, tooltip, slice] + ) + + const handleMouseLeave = useCallback(() => { + hideTooltip() + setCurrent(null) + }, [hideTooltip]) + + return ( + + ) +}) + +SlicesItem.displayName = 'SlicesItem' +SlicesItem.propTypes = { + slice: PropTypes.object.isRequired, + axis: PropTypes.oneOf(['x', 'y']).isRequired, + debug: PropTypes.bool.isRequired, + height: PropTypes.number.isRequired, + tooltip: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + isCurrent: PropTypes.bool.isRequired, +} + +export default SlicesItem diff --git a/packages/line/src/hooks.js b/packages/line/src/hooks.js index 0579872b7..723ace9ec 100644 --- a/packages/line/src/hooks.js +++ b/packages/line/src/hooks.js @@ -13,6 +13,132 @@ import { useOrdinalColorScale, useInheritedColor } from '@nivo/colors' import { computeXYScalesForSeries, computeYSlices } from '@nivo/scales' import { LineDefaultProps } from './props' +export const useLineGenerator = ({ curve }) => { + return useMemo( + () => + line() + .defined(d => d.x !== null && d.y !== null) + .x(d => d.x) + .y(d => d.y) + .curve(curveFromProp(curve)), + [curve] + ) +} + +export const useAreaGenerator = ({ curve, yScale, areaBaselineValue }) => { + return useMemo(() => { + return area() + .defined(d => d.x !== null && d.y !== null) + .x(d => d.x) + .y1(d => d.y) + .curve(curveFromProp(curve)) + .y0(yScale(areaBaselineValue)) + }, [curve, yScale, areaBaselineValue]) +} + +const usePoints = ({ series, getPointColor, getPointBorderColor, formatX, formatY }) => { + return useMemo(() => { + return series.reduce((acc, serie) => { + return [ + ...acc, + ...serie.data + .filter(datum => datum.position.x !== null && datum.position.y !== null) + .map((datum, i) => { + const point = { + id: `${serie.id}.${i}`, + index: acc.length + i, + serieId: serie.id, + serieColor: serie.color, + x: datum.position.x, + y: datum.position.y, + } + point.color = getPointColor(serie) + point.borderColor = getPointBorderColor(point) + point.data = { + ...datum.data, + xFormatted: formatX(datum.data.x), + yFormatted: formatY(datum.data.y), + } + + return point + }), + ] + }, []) + }, [series, getPointColor, getPointBorderColor, formatX, formatY]) +} + +export const useSlices = ({ enableSlices, points, width, height }) => { + return useMemo(() => { + if (enableSlices === false) return [] + + if (enableSlices === 'x') { + const map = new Map() + points.forEach(point => { + if (point.data.x === null || point.data.y === null) return + if (!map.has(point.x)) map.set(point.x, [point]) + else map.get(point.x).push(point) + }) + return Array.from(map.entries()) + .sort((a, b) => a[0] - b[0]) + .map(([x, slicePoints], i, slices) => { + const prevSlice = slices[i - 1] + const nextSlice = slices[i + 1] + + let x0 + if (!prevSlice) x0 = x + else x0 = x - (x - prevSlice[0]) / 2 + + let sliceWidth + if (!nextSlice) sliceWidth = width - x0 + else sliceWidth = x - x0 + (nextSlice[0] - x) / 2 + + return { + id: x, + x0, + x, + y0: 0, + y: 0, + width: sliceWidth, + height, + points: slicePoints.reverse(), + } + }) + } else if (enableSlices === 'y') { + const map = new Map() + points.forEach(point => { + if (point.data.x === null || point.data.y === null) return + if (!map.has(point.y)) map.set(point.y, [point]) + else map.get(point.y).push(point) + }) + return Array.from(map.entries()) + .sort((a, b) => a[0] - b[0]) + .map(([y, slicePoints], i, slices) => { + const prevSlice = slices[i - 1] + const nextSlice = slices[i + 1] + + let y0 + if (!prevSlice) y0 = y + else y0 = y - (y - prevSlice[0]) / 2 + + let sliceHeight + if (!nextSlice) sliceHeight = height - y0 + else sliceHeight = y - y0 + (nextSlice[0] - y) / 2 + + return { + id: y, + x0: 0, + x: 0, + y0, + y, + width, + height: sliceHeight, + points: slicePoints.reverse(), + } + }) + } + }, [enableSlices, points]) +} + export const useLine = ({ data, xScale: xScaleSpec = LineDefaultProps.xScale, @@ -26,17 +152,16 @@ export const useLine = ({ areaBaselineValue = LineDefaultProps.areaBaselineValue, pointColor = LineDefaultProps.pointColor, pointBorderColor = LineDefaultProps.pointBorderColor, + enableSlices = LineDefaultProps.enableSlicesTooltip, }) => { + const formatX = useValueFormatter(xFormat) + const formatY = useValueFormatter(yFormat) const getColor = useOrdinalColorScale(colors, 'id') - const lineGenerator = useMemo(() => { - return line() - .defined(d => d.x !== null && d.y !== null) - .x(d => d.x) - .y(d => d.y) - .curve(curveFromProp(curve)) - }, [curve]) + const theme = useTheme() + const getPointColor = useInheritedColor(pointColor, theme) + const getPointBorderColor = useInheritedColor(pointBorderColor, theme) - const { x: xValues, xScale, yScale, series: rawSeries } = useMemo( + const { xScale, yScale, series: rawSeries } = useMemo( () => computeXYScalesForSeries(data, xScaleSpec, yScaleSpec, width, height), [data, xScaleSpec, yScaleSpec, width, height] ) @@ -50,16 +175,27 @@ export const useLine = ({ [rawSeries, getColor] ) - const slices = useMemo(() => computeYSlices({ series, x: xValues, xScale }), [series, xValues]) + const points = usePoints({ + series, + getPointColor, + getPointBorderColor, + formatX, + formatY, + }) - const areaGenerator = useMemo(() => { - return area() - .defined(d => d.x !== null && d.y !== null) - .x(d => d.x) - .y1(d => d.y) - .curve(curveFromProp(curve)) - .y0(yScale(areaBaselineValue)) - }, [curve, yScale, areaBaselineValue]) + const slices = useSlices({ + enableSlices, + points, + width, + height, + }) + + const lineGenerator = useLineGenerator({ curve }) + const areaGenerator = useAreaGenerator({ + curve, + yScale, + areaBaselineValue, + }) return { lineGenerator, @@ -69,51 +205,6 @@ export const useLine = ({ xScale, yScale, slices, + points, } } - -export const useLinePoints = ({ - isEnabled = true, - series, - xFormat, - yFormat, - color = LineDefaultProps.pointColor, - borderColor = LineDefaultProps.pointBorderColor, -}) => { - const theme = useTheme() - const getColor = useInheritedColor(color, theme) - const getBorderColor = useInheritedColor(borderColor, theme) - const formatX = useValueFormatter(xFormat) - const formatY = useValueFormatter(yFormat) - - return useMemo(() => { - if (isEnabled !== true) return [] - - return series.reduce((acc, serie) => { - return [ - ...acc, - ...serie.data - .filter(datum => datum.position.x !== null && datum.position.y !== null) - .map((datum, i) => { - const point = { - id: `${serie.id}.${i}`, - index: acc.length + i, - serieId: serie.id, - serieColor: serie.color, - x: datum.position.x, - y: datum.position.y, - } - point.color = getColor(serie) - point.borderColor = getBorderColor(point) - point.data = { - ...datum.data, - xFormatted: formatX(datum.data.x), - yFormatted: formatY(datum.data.y), - } - - return point - }), - ] - }, []) - }, [series, getColor, getBorderColor, formatX, formatY]) -} diff --git a/packages/line/src/props.js b/packages/line/src/props.js index 50f72fe0a..2e6a10617 100644 --- a/packages/line/src/props.js +++ b/packages/line/src/props.js @@ -13,8 +13,8 @@ import { axisPropType } from '@nivo/axes' import { scalePropType } from '@nivo/scales' import { LegendPropShape } from '@nivo/legends' import { crosshairPropTypes } from '@nivo/tooltip' -import LinePointTooltip from './LinePointTooltip' -import LineStackedTooltip from './LineStackedTooltip' +import PointTooltip from './PointTooltip' +import SliceTooltip from './SliceTooltip' const commonPropTypes = { data: PropTypes.arrayOf( @@ -98,6 +98,7 @@ const commonPropTypes = { ), colors: ordinalColorsPropType.isRequired, + enableArea: PropTypes.bool.isRequired, areaOpacity: PropTypes.number.isRequired, areaBlendMode: blendModePropType.isRequired, @@ -117,10 +118,13 @@ const commonPropTypes = { isInteractive: PropTypes.bool.isRequired, debugMesh: PropTypes.bool.isRequired, + tooltip: PropTypes.oneOfType([PropTypes.func, PropTypes.object]).isRequired, tooltipFormat: PropTypes.oneOfType([PropTypes.func, PropTypes.string]), - enableStackTooltip: PropTypes.bool.isRequired, - stackTooltip: PropTypes.oneOfType([PropTypes.func, PropTypes.object]).isRequired, + + enableSlices: PropTypes.oneOf(['x', 'y', false]).isRequired, + debugSlices: PropTypes.bool.isRequired, + sliceTooltip: PropTypes.oneOfType([PropTypes.func, PropTypes.object]).isRequired, enableCrosshair: PropTypes.bool.isRequired, crosshairType: crosshairPropTypes.type.isRequired, @@ -157,8 +161,8 @@ const commonDefaultProps = { 'areas', 'crosshair', 'lines', - 'slices', 'points', + 'slices', 'mesh', 'legends', ], @@ -185,11 +189,11 @@ const commonDefaultProps = { legends: [], isInteractive: true, - tooltip: LinePointTooltip, - enableStackTooltip: false, - stackTooltip: LineStackedTooltip, + tooltip: PointTooltip, + enableSlices: false, + debugSlices: false, + sliceTooltip: SliceTooltip, debugMesh: false, - enableCrosshair: true, crosshairType: 'bottom-left', } diff --git a/packages/line/stories/line.stories.js b/packages/line/stories/line.stories.js index 1ddca0e3b..11b3bbb9d 100644 --- a/packages/line/stories/line.stories.js +++ b/packages/line/stories/line.stories.js @@ -25,7 +25,7 @@ const commonProperties = { margin: { top: 20, right: 20, bottom: 60, left: 80 }, data, animate: true, - enableStackTooltip: true, + enableSlices: 'x', } const curveOptions = ['linear', 'monotoneX', 'step', 'stepBefore', 'stepAfter'] @@ -179,7 +179,7 @@ stories.add('time scale', () => ( modifiers: [['darker', 0.3]], }} useMesh={true} - enableStackTooltip={false} + enableSlices={false} /> )) @@ -221,7 +221,7 @@ stories.add('logarithmic scale', () => ( legendOffset: 12, }} useMesh={true} - enableStackTooltip={false} + enableSlices={false} /> )) @@ -313,7 +313,7 @@ class RealTimeChart extends Component { motionStiffness={120} motionDamping={50} isInteractive={false} - enableStackTooltip={false} + enableSlices={false} useMesh={true} theme={{ axis: { ticks: { text: { fontSize: 14 } } }, @@ -410,7 +410,7 @@ stories.add('using data colors', () => ( pointSize={10} pointBorderColor={{ theme: 'background' }} pointBorderWidth={2} - enableStackTooltip={false} + enableSlices={false} useMesh={true} /> )) @@ -640,7 +640,7 @@ stories.add('non linear values', () => ( pointColor="white" pointBorderColor={{ from: 'serieColor' }} pointBorderWidth={2} - enableStackTooltip={false} + enableSlices={false} useMesh={true} debugMesh={true} data={[ @@ -770,6 +770,9 @@ stories.add( }} enableArea={true} areaOpacity={0.07} + enableSlices={false} + useMesh={true} + crosshairType="cross" /> ), { @@ -819,13 +822,13 @@ stories.add('formatting tooltip values', () => ( stories.add('custom tooltip', () => ( ( + sliceTooltip={({ slice }) => (
{} + + export type CrosshairType = + | 'x' + | 'y' + | 'top-left' + | 'top' + | 'top-right' + | 'right' + | 'bottom-right' + | 'bottom' + | 'bottom-left' + | 'left' + | 'cross' } diff --git a/packages/tooltip/src/components/Crosshair.js b/packages/tooltip/src/components/Crosshair.js index ff8fd6bbb..cee4da920 100644 --- a/packages/tooltip/src/components/Crosshair.js +++ b/packages/tooltip/src/components/Crosshair.js @@ -76,6 +76,10 @@ const Crosshair = memo(({ width, height, type, x, y, animate, motionStiffness, m yLine = { x0: 0, x1: x, y0: y, y1: y } } else if (type === 'left') { yLine = { x0: 0, x1: x, y0: y, y1: y } + } else if (type === 'x') { + xLine = { x0: x, x1: x, y0: 0, y1: height } + } else if (type === 'y') { + yLine = { x0: 0, x1: width, y0: y, y1: y } } return ( diff --git a/packages/tooltip/src/props.js b/packages/tooltip/src/props.js index 835381e4c..17d156f40 100644 --- a/packages/tooltip/src/props.js +++ b/packages/tooltip/src/props.js @@ -9,7 +9,8 @@ import PropTypes from 'prop-types' export const crosshairTypes = [ - 'cross', + 'x', + 'y', 'top-left', 'top', 'top-right', @@ -18,6 +19,7 @@ export const crosshairTypes = [ 'bottom', 'bottom-left', 'left', + 'cross', ] export const crosshairPropTypes = { diff --git a/website/src/components/controls/ChoicesControl.js b/website/src/components/controls/ChoicesControl.js index 5fc057ab9..a98224f5d 100644 --- a/website/src/components/controls/ChoicesControl.js +++ b/website/src/components/controls/ChoicesControl.js @@ -32,7 +32,7 @@ ChoicesControl.propTypes = { property: PropTypes.object.isRequired, flavors: PropTypes.arrayOf(PropTypes.oneOf(['svg', 'html', 'canvas', 'api'])).isRequired, currentFlavor: PropTypes.oneOf(['svg', 'html', 'canvas', 'api']).isRequired, - value: PropTypes.string.isRequired, + value: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.bool]).isRequired, onChange: PropTypes.func.isRequired, } diff --git a/website/src/components/controls/Switch.js b/website/src/components/controls/Switch.js index e522afd87..072da4fa8 100644 --- a/website/src/components/controls/Switch.js +++ b/website/src/components/controls/Switch.js @@ -11,10 +11,7 @@ import PropTypes from 'prop-types' import styled from 'styled-components' const Switch = memo(({ id, value, onChange, colors = {} }) => { - const handleChange = useCallback( - event => onChange(event.target.checked), - [onChange] - ) + const handleChange = useCallback(event => onChange(event.target.checked), [onChange]) return ( diff --git a/website/src/data/components/line/defaults.js b/website/src/data/components/line/defaults.js index 7a42e1a3c..e4b761a6b 100644 --- a/website/src/data/components/line/defaults.js +++ b/website/src/data/components/line/defaults.js @@ -90,7 +90,8 @@ export default { areaOpacity: 0.2, isInteractive: true, - enableStackTooltip: false, + enableSlices: 'x', + debugSlices: false, enableCrosshair: true, crosshairType: 'bottom-left', diff --git a/website/src/data/components/line/meta.yml b/website/src/data/components/line/meta.yml index ce24eaee9..5f5c1996f 100644 --- a/website/src/data/components/line/meta.yml +++ b/website/src/data/components/line/meta.yml @@ -24,6 +24,8 @@ Line: link: line--real-time-chart - label: custom point symbol link: line--custom-point-symbol + - label: none linear values + link: line--non-linear-values - label: adding markers link: line--adding-markers - label: holes in data diff --git a/website/src/data/components/line/props.js b/website/src/data/components/line/props.js index 168b7abbc..0c281177b 100644 --- a/website/src/data/components/line/props.js +++ b/website/src/data/components/line/props.js @@ -492,20 +492,46 @@ const props = [ required: false, }, { - key: 'enableStackTooltip', + key: 'enableSlices', + group: 'Interactivity', + flavors: ['svg', 'canvas'], + help: `Enable/disable slices tooltip for x or y axis, automatically disable mesh.`, + type: `'x' | 'y' | false`, + required: false, + defaultValue: defaults.enableSlicesTooltip, + controlType: 'choices', + controlOptions: { + choices: [ + { + label: 'false', + value: false, + }, + { + label: 'x', + value: 'x', + }, + { + label: 'y', + value: 'y', + }, + ], + }, + }, + { + key: 'debugSlices', flavors: ['svg', 'canvas'], - help: `Enable/disable stack tooltip, it also disable mesh.`, + help: 'Display area used to detect mouse interactions for slices.', type: 'boolean', required: false, - defaultValue: defaults.enableStackTooltip, + defaultValue: defaults.debugSlices, controlType: 'switch', group: 'Interactivity', }, { - key: 'stackTooltip', + key: 'sliceTooltip', flavors: ['svg', 'canvas'], group: 'Interactivity', - help: `Custom stack tooltip`, + help: `Custom slice tooltip`, type: 'Function', required: false, }, @@ -525,12 +551,14 @@ const props = [ group: 'Interactivity', required: false, defaultValue: defaults.crosshairType, - help: `Crosshair type, non customizable when stack tooltip is enabled.`, + help: `Crosshair type, forced to slices axis if enabled.`, type: 'string', controlType: 'choices', controlOptions: { disabled: true, choices: [ + 'x', + 'y', 'top-left', 'top', 'top-right', diff --git a/website/src/data/nav.js b/website/src/data/nav.js index fbf93a0a8..f3965373b 100644 --- a/website/src/data/nav.js +++ b/website/src/data/nav.js @@ -31,121 +31,121 @@ import waffle from './components/waffle/meta.yml' export const components = [ { label: 'Bar', - path: '/bar', + path: '/bar/', icon: 'bar', tags: bar.Bar.tags, }, { label: 'Bubble', - path: '/bubble', + path: '/bubble/', icon: 'circle-packing', tags: bubble.Bubble.tags, }, { label: 'Bullet', - path: '/bullet', + path: '/bullet/', icon: 'bullet', tags: bullet.Bullet.tags, }, { label: 'Calendar', - path: '/calendar', + path: '/calendar/', icon: 'calendar', tags: calendar.Calendar.tags, }, { label: 'Choropleth', - path: '/choropleth', + path: '/choropleth/', icon: 'choropleth', tags: choropleth.Choropleth.tags, }, { label: 'Chord', - path: '/chord', + path: '/chord/', icon: 'chord', tags: chord.Chord.tags, }, { label: 'GeoMap', - path: '/geomap', + path: '/geomap/', icon: 'geomap', tags: geomap.GeoMap.tags, }, { label: 'HeatMap', - path: '/heatmap', + path: '/heatmap/', icon: 'heatmap', tags: heatmap.HeatMap.tags, }, { label: 'Line', - path: '/line', + path: '/line/', icon: 'line', tags: line.Line.tags, }, { label: 'ParallelCoordinates', - path: '/parallel-coordinates', + path: '/parallel-coordinates/', icon: 'parallel-coordinates', tags: parallelCoordinates.ParallelCoordinates.tags, }, { label: 'Pie', - path: '/pie', + path: '/pie/', icon: 'pie', tags: pie.Pie.tags, }, { label: 'Radar', - path: '/radar', + path: '/radar/', icon: 'radar', tags: radar.Radar.tags, }, { label: 'Sankey', - path: '/sankey', + path: '/sankey/', icon: 'sankey', tags: sankey.Sankey.tags, }, { label: 'ScatterPlot', - path: '/scatterplot', + path: '/scatterplot/', icon: 'scatterplot', tags: scatterplot.ScatterPlot.tags, }, { label: 'Stream', - path: '/stream', + path: '/stream/', icon: 'stream', tags: stream.Stream.tags, }, { label: 'Sunburst', - path: '/sunburst', + path: '/sunburst/', icon: 'sunburst', tags: sunburst.Sunburst.tags, }, { label: 'SwarmPlot', - path: '/swarmplot', + path: '/swarmplot/', icon: 'swarmplot', tags: swarmplot.SwarmPlot.tags, }, { label: 'TreeMap', - path: '/treemap', + path: '/treemap/', icon: 'treemap', tags: treemap.TreeMap.tags, }, { label: 'Voronoi', - path: '/voronoi', + path: '/voronoi/', icon: 'voronoi', tags: voronoi.Voronoi.tags, }, { label: 'Waffle', - path: '/waffle', + path: '/waffle/', icon: 'waffle', tags: waffle.Waffle.tags, }, @@ -154,169 +154,169 @@ export const components = [ const all = components.concat([ { label: 'BarCanvas', - path: '/bar/canvas', + path: '/bar/canvas/', icon: 'bar', tags: bar.BarCanvas.tags, }, { label: 'Bar HTTP API', - path: '/bar/api', + path: '/bar/api/', icon: 'bar', tags: [...bar.Bar.tags, 'HTTP API'], }, { label: 'BubbleHtml', - path: '/bubble/html', + path: '/bubble/html/', icon: 'circle-packing', tags: bubble.BubbleHtml.tags, }, { label: 'BubbleCanvas', - path: '/bubble/canvas', + path: '/bubble/canvas/', icon: 'circle-packing', tags: bubble.BubbleCanvas.tags, }, { label: 'Bubble HTTP API', - path: '/bubble/api', + path: '/bubble/api/', icon: 'circle-packing', tags: [...bubble.Bubble.tags, 'HTTP API'], }, { label: 'CalendarCanvas', - path: '/calendar/canvas', + path: '/calendar/canvas/', icon: 'calendar', tags: calendar.CalendarCanvas.tags, }, { label: 'Calendar HTTP API', - path: '/calendar/api', + path: '/calendar/api/', icon: 'calendar', tags: [...calendar.Calendar.tags, 'HTTP API'], }, { label: 'ChoroplethCanvas', - path: '/choropleth/canvas', + path: '/choropleth/canvas/', icon: 'choropleth', tags: choropleth.ChoroplethCanvas.tags, }, { label: 'ChordCanvas', - path: '/chord/canvas', + path: '/chord/canvas/', icon: 'chord', tags: chord.ChordCanvas.tags, }, { label: 'Chord HTTP API', - path: '/chord/api', + path: '/chord/api/', icon: 'chord', tags: [...chord.Chord.tags, 'HTTP API'], }, { label: 'GeoMapCanvas', - path: '/geomap/canvas', + path: '/geomap/canvas/', icon: 'geomap', tags: geomap.GeoMapCanvas.tags, }, { label: 'HeatMapCanvas', - path: '/heatmap/canvas', + path: '/heatmap/canvas/', icon: 'heatmap', tags: heatmap.HeatMapCanvas.tags, }, { label: 'HeatMap HTTP API', - path: '/heatmap/api', + path: '/heatmap/api/', icon: 'heatmap', tags: [...heatmap.HeatMap.tags, 'HTTP API'], }, { label: 'LineCanvas', - path: '/line/canvas', + path: '/line/canvas/', icon: 'line', tags: line.LineCanvas.tags, }, { label: 'Line HTTP API', - path: '/line/api', + path: '/line/api/', icon: 'line', tags: [...line.Line.tags, 'HTTP API'], }, { label: 'ParallelCoordinatesCanvas', - path: '/parallel-coordinates/canvas', + path: '/parallel-coordinates/canvas/', icon: 'parallel-coordinates', tags: parallelCoordinates.ParallelCoordinatesCanvas.tags, }, { label: 'PieCanvas', - path: '/pie/canvas', + path: '/pie/canvas/', icon: 'pie', tags: pie.PieCanvas.tags, }, { label: 'Pie HTTP API', - path: '/pie/api', + path: '/pie/api/', icon: 'pie', tags: [...pie.Pie.tags, 'HTTP API'], }, { label: 'Radar HTTP API', - path: '/radar/api', + path: '/radar/api/', icon: 'radar', tags: [...radar.Radar.tags, 'HTTP API'], }, { label: 'Sankey HTTP API', - path: '/sankey/api', + path: '/sankey/api/', icon: 'sankey', tags: [...sankey.Sankey.tags, 'HTTP API'], }, { label: 'ScatterPlotCanvas', - path: '/scatterplot/canvas', + path: '/scatterplot/canvas/', icon: 'scatterplot', tags: scatterplot.ScatterPlotCanvas.tags, }, { label: 'Sunburst HTTP API', - path: '/sunburst/api', + path: '/sunburst/api/', icon: 'sunburst', tags: [...sunburst.Sunburst.tags, 'HTTP API'], }, { label: 'SwarmPlotCanvas', - path: '/swarmplot/canvas', + path: '/swarmplot/canvas/', icon: 'swarmplot', tags: swarmplot.SwarmPlotCanvas.tags, }, { label: 'TreeMapHtml', - path: '/treemap/html', + path: '/treemap/html/', icon: 'treemap', tags: treemap.TreeMapHtml.tags, }, { label: 'TreeMapCanvas', - path: '/treemap/canvas', + path: '/treemap/canvas/', icon: 'treemap', tags: treemap.TreeMapCanvas.tags, }, { label: 'TreeMap HTTP API', - path: '/treemap/api', + path: '/treemap/api/', icon: 'treemap', tags: [...treemap.TreeMap.tags, 'HTTP API'], }, { label: 'WaffleHtml', - path: '/waffle/html', + path: '/waffle/html/', icon: 'waffle', tags: waffle.WaffleHtml.tags, }, { label: 'WaffleCanvas', - path: '/waffle/canvas', + path: '/waffle/canvas/', icon: 'waffle', tags: waffle.WaffleCanvas.tags, }, diff --git a/website/src/pages/bar/index.js b/website/src/pages/bar/index.js index 2d119f3f0..2bbc0959d 100644 --- a/website/src/pages/bar/index.js +++ b/website/src/pages/bar/index.js @@ -11,7 +11,7 @@ import { patternDotsDef, patternLinesDef } from '@nivo/core' import { ResponsiveBar, BarDefaultProps } from '@nivo/bar' import ComponentTemplate from '../../components/components/ComponentTemplate' import meta from '../../data/components/bar/meta.yml' -//import { generateLightDataSet } from '../../data/components/bar/generator' +import { generateLightDataSet } from '../../data/components/bar/generator' import mapper from '../../data/components/bar/mapper' import { groups } from '../../data/components/bar/props' @@ -19,27 +19,8 @@ const Tooltip = () => { /* return custom tooltip */ } -const generateLightDataSet = () => { - return { - keys: ["key1", "key2", "key3", "key4", "key5", "key6", "key7", "key8"], - data: [ - { - key1: 9512.0976, - key2: 4000.0032, - key3: 3.4515, - key4: 107.1447, - key5: 4000.0032, - key6: 0, - key7: 0, - key8: 321.4296, - time: "2019-04" - } - ] - } -} - const initialProperties = { - indexBy: 'time', + indexBy: 'country', margin: { top: 50, @@ -53,7 +34,7 @@ const initialProperties = { minValue: 'auto', maxValue: 'auto', - groupMode: 'grouped', + groupMode: 'stacked', layout: 'vertical', reverse: false, diff --git a/website/src/pages/line/api.js b/website/src/pages/line/api.js index c0e42e1b6..c454da90f 100644 --- a/website/src/pages/line/api.js +++ b/website/src/pages/line/api.js @@ -31,7 +31,13 @@ const LineApi = () => { controlGroups={groups} propsMapper={mapper} defaultProps={{ - ...omit(defaultSettings, ['isInteractive', 'enableStackTooltip']), + ...omit(defaultSettings, [ + 'isInteractive', + 'enableSlices', + 'debugSlices', + 'enableCrosshair', + 'crosshairType', + ]), data: JSON.stringify(data, null, ' '), }} /> diff --git a/website/src/pages/line/index.js b/website/src/pages/line/index.js index fd7f102cc..08cc39a36 100644 --- a/website/src/pages/line/index.js +++ b/website/src/pages/line/index.js @@ -74,7 +74,7 @@ const Line = () => { data={data} {...properties} theme={theme} - enableStackTooltip={true} + yFormat=".2f" onClick={point => { logAction({ type: 'click',