Skip to content

Commit

Permalink
new(vx-demo/vx-axis): update demo to use AnimatedAxis
Browse files Browse the repository at this point in the history
  • Loading branch information
williaster committed Aug 19, 2020
1 parent a75cd1e commit 92a1b2e
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 83 deletions.
2 changes: 2 additions & 0 deletions packages/vx-demo/src/components/Gallery/AxisTile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@ export { default as packageJson } from '../../sandboxes/vx-axis/package.json';

const tileStyles = { backgroundColor };
const detailsStyles = { color: labelColor };
const exampleProps = { showControls: false };

export default function AxisTile() {
return (
<GalleryTile<AxisProps>
title="Axes & scales"
description="<Axis.AxisBottom />"
detailsStyles={detailsStyles}
exampleProps={exampleProps}
exampleRenderer={Axis}
exampleUrl="/axis"
tileStyles={tileStyles}
Expand Down
3 changes: 2 additions & 1 deletion packages/vx-demo/src/pages/docs/axis.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react';
import AxisReadme from '!!raw-loader!../../../../vx-axis/Readme.md';
import Axis from '../../../../vx-axis/src/axis/Axis';
import AnimatedAxis from '../../../../vx-axis/src/axis/AnimatedAxis';
import AxisBottom from '../../../../vx-axis/src/axis/AxisBottom';
import AxisLeft from '../../../../vx-axis/src/axis/AxisLeft';
import AxisRight from '../../../../vx-axis/src/axis/AxisRight';
Expand All @@ -10,7 +11,7 @@ import AxisTile from '../../components/Gallery/AxisTile';
import BarStackTile from '../../components/Gallery/BarStackTile';
import ThresholdTile from '../../components/Gallery/ThresholdTile';

const components = [Axis, AxisBottom, AxisLeft, AxisRight, AxisTop];
const components = [Axis, AnimatedAxis, AxisBottom, AxisLeft, AxisRight, AxisTop];

const examples = [AxisTile, BarStackTile, ThresholdTile];

Expand Down
191 changes: 109 additions & 82 deletions packages/vx-demo/src/sandboxes/vx-axis/Example.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import React from 'react';
import React, { useState } from 'react';
import AreaClosed from '@vx/shape/lib/shapes/AreaClosed';
import { Grid } from '@vx/grid';
import { curveMonotoneX } from '@vx/curve';
import { scaleUtc, scaleLinear, scaleLog, scaleBand, ScaleInput } from '@vx/scale';
import { AxisBottom, SharedAxisProps, AxisScale } from '@vx/axis';
import { scaleUtc, scaleLinear, scaleLog, scaleBand, ScaleInput, coerceNumber } from '@vx/scale';
import { AnimatedAxis, Orientation, SharedAxisProps, AxisScale } from '@vx/axis';
import { LinearGradient } from '@vx/gradient';
import { timeFormat } from 'd3-time-format';

Expand All @@ -20,60 +20,83 @@ const margin = {
left: 50,
};

const getMinMax = (vals: (number | { valueOf(): number })[]) => {
const numericVals = vals.map(coerceNumber);
return [Math.min(...numericVals), Math.max(...numericVals)];
};

export type AxisProps = {
width: number;
height: number;
showControls?: boolean;
};

export default function Example({ width: outerWidth = 800, height: outerHeight = 800 }: AxisProps) {
export default function Example({
width: outerWidth = 800,
height: outerHeight = 800,
showControls = true,
}: AxisProps) {
// in svg, margin is subtracted from total width/height
const width = outerWidth - margin.left - margin.right;
const height = outerHeight - margin.top - margin.bottom;
const [dataToggle, setDataToggle] = useState(true);

if (width < 10) return null;

interface AxisDemoProps<Scale extends AxisScale> extends SharedAxisProps<Scale> {
values: ScaleInput<Scale>[];
}

// toggle between two value ranges to demo animation
const linearValues = dataToggle ? [0, 2, 4, 6, 8, 10] : [6, 8, 10, 12];
const bandValues = dataToggle ? ['a', 'b', 'c', 'd'] : ['d', 'c', 'b', 'a'];
const timeValues = dataToggle
? [new Date('2020-01-01'), new Date('2020-02-01')]
: [new Date('2020-02-01'), new Date('2020-03-01')];
const logValues = dataToggle ? [1, 10, 100, 1000, 10000] : [0.0001, 0.001, 0.1, 1, 10, 100];

const axes: AxisDemoProps<AxisScale<number>>[] = [
{
scale: scaleLinear({
domain: [0, 10],
domain: getMinMax(linearValues),
range: [0, width],
}),
values: [0, 2, 4, 6, 8, 10],
tickFormat: (v: number) => (v === 10 ? 'last' : (v === 0 && 'first') || `${v}`),
values: linearValues,
tickFormat: (v: number, index: number, ticks: { value: number; index: number }[]) =>
index === 0 ? 'first' : index === ticks[ticks.length - 1].index ? 'last' : `${v}`,
label: 'linear',
},
{
scale: scaleBand({
domain: ['a', 'b', 'c', 'd'],
domain: bandValues,
range: [0, width],
paddingOuter: 0,
paddingInner: 1,
}),
values: ['a', 'b', 'c', 'd'],
values: bandValues,
tickFormat: (v: string) => v,
label: 'categories',
},
{
scale: scaleUtc({
domain: [new Date('2020-01-01'), new Date('2020-03-01')],
domain: getMinMax(timeValues),
range: [0, width],
}),
values: [new Date('2020-01-01'), new Date('2020-02-01'), new Date('2020-03-01')],
values: timeValues,
tickFormat: (v: Date, i: number) =>
v.getDate() === 1 ? '🎉' : width > 400 || i % 2 === 0 ? timeFormat('%b %d')(v) : '',
i === 3 ? '🎉' : width > 400 || i % 2 === 0 ? timeFormat('%b %d')(v) : '',
label: 'time',
},
{
scale: scaleLog({
domain: [1, 10000],
domain: getMinMax(logValues),
range: [0, width],
}),
values: [1, 10, 100, 1000, 10000],
tickFormat: (v: number) => (`${v}`[0] === '1' ? `${v}` : ''),
values: logValues,
tickFormat: (v: number) => {
const asString = `${v}`;
return asString.match(/^[10\]\.?[01]*$/) ? asString : '';
},
label: 'log',
},
];
Expand All @@ -87,76 +110,80 @@ export default function Example({ width: outerWidth = 800, height: outerHeight =
});

return (
<svg width={outerWidth} height={outerHeight}>
<LinearGradient
id="vx-axis-gradient"
from={backgroundColor}
to={backgroundColor}
toOpacity={0.5}
/>
<rect
x={0}
y={0}
width={outerWidth}
height={outerHeight}
fill={'url(#vx-axis-gradient)'}
rx={14}
/>
<g transform={`translate(${margin.left},${margin.top})`}>
{axes.map(({ scale, values, label, tickFormat }, i) => (
<g key={`scale-${i}`} transform={`translate(0, ${i * (scaleHeight + scalePadding)})`}>
<AreaClosed
data={values.map(x => [
(scale(x) ?? 0) +
('bandwidth' in scale && typeof scale!.bandwidth !== 'undefined'
? scale.bandwidth!() / 2
: 0),
yScale(10 + Math.random() * 90),
])}
yScale={yScale}
curve={curveMonotoneX}
fill={gridColor}
fillOpacity={0.2}
/>
<Grid
xScale={scale}
yScale={yScale}
stroke={gridColor}
width={width}
height={scaleHeight}
numTicksRows={2}
numTicksColumns={numTickColumns}
/>
<AxisBottom
top={scaleHeight}
scale={scale}
tickFormat={tickFormat}
stroke={axisColor}
tickStroke={axisColor}
tickLabelProps={
(/* value, index */) => ({
<>
<svg width={outerWidth} height={outerHeight}>
<LinearGradient
id="vx-axis-gradient"
from={backgroundColor}
to={backgroundColor}
toOpacity={0.5}
/>
<rect
x={0}
y={0}
width={outerWidth}
height={outerHeight}
fill={'url(#vx-axis-gradient)'}
rx={14}
/>
<g transform={`translate(${margin.left},${margin.top})`}>
{axes.map(({ scale, values, label, tickFormat }, i) => (
<g key={`scale-${i}`} transform={`translate(0, ${i * (scaleHeight + scalePadding)})`}>
<AreaClosed
data={values.map(x => [
(scale(x) ?? 0) +
('bandwidth' in scale && typeof scale!.bandwidth !== 'undefined'
? scale.bandwidth!() / 2
: 0),
yScale(10 + Math.random() * 90),
])}
yScale={yScale}
curve={curveMonotoneX}
fill={gridColor}
fillOpacity={0.2}
/>
<Grid
xScale={scale}
yScale={yScale}
stroke={gridColor}
width={width}
height={scaleHeight}
numTicksRows={2}
numTicksColumns={numTickColumns}
/>
<AnimatedAxis
orientation={Orientation.bottom}
top={scaleHeight}
scale={scale}
tickFormat={tickFormat}
stroke={axisColor}
tickStroke={axisColor}
tickLabelProps={() => ({
fill: tickLabelColor,
fontSize: 12,
fontFamily: 'sans-serif',
textAnchor: 'middle',
})
}
label={label}
labelProps={{
x: width + 30,
y: -10,
fill: labelColor,
fontSize: 18,
strokeWidth: 0,
stroke: '#fff',
paintOrder: 'stroke',
fontFamily: 'sans-serif',
textAnchor: 'start',
}}
/>
</g>
))}
</g>
</svg>
})}
tickValues={label === 'log' || label === 'time' ? undefined : values}
numTicks={label === 'time' ? 6 : undefined}
label={label}
labelProps={{
x: width + 30,
y: -10,
fill: labelColor,
fontSize: 18,
strokeWidth: 0,
stroke: '#fff',
paintOrder: 'stroke',
fontFamily: 'sans-serif',
textAnchor: 'start',
}}
/>
</g>
))}
</g>
</svg>
{showControls && <button onClick={() => setDataToggle(!dataToggle)}>Update scales</button>}
</>
);
}

0 comments on commit 92a1b2e

Please sign in to comment.