Airbnb introduces visx ๐ฏ
visx ๐
Airbnb has created a new open source product called visx. After 3 years of development, 2.5 years of production use and a rewrite in TypeScript they finally released it 22 September 2020.
visx is a collection of reusable low-level visualization components. visx combines the power of d3 to generate your visualization with the benefits of react for updating the DOM.
Just another charting library? ๐
No, actually not. It's more of a complex and reusable visualization system. You can create your own charting library based on visx.
Not a charting library. As you start using visualization primitives, youโll end up building your own charting library thatโs optimized for your use case. Youโre in control.
Demo ๐ฅ
There's a lot to demo, but for fun and to prove that it's not a charting library I'll show you the possibility to draw something.
Implementation
The demo is highly based on their own showcase. If you want to take a look at my own tweak of their demo, you can do that here.
This is how their showcase looks like:
import React, { useState } from 'react';
import { LinePath } from '@visx/shape';
import { Drag } from '@visx/drag';
import { curveBasis } from '@visx/curve';
import { LinearGradient } from '@visx/gradient';
type Line = { x: number; y: number }[];
type Lines = Line[];
export type DragIIProps = {
width: number;
height: number;
data?: Lines;
};
export default function DragII({ data = [], width, height }: DragIIProps) {
const [lines, setLines] = useState<Lines>(data);
return width < 10 ? null : (
<div className="DragII" style={{ touchAction: 'none' }}>
<svg width={width} height={height}>
<LinearGradient id="stroke" from="#ff614e" to="#ffdc64" />
<rect fill="#04002b" width={width} height={height} rx={14} />
{lines.map((line, i) => (
<LinePath
key={`line-${i}`}
fill="transparent"
stroke="url(#stroke)"
strokeWidth={3}
data={line}
curve={curveBasis}
x={(d) => d.x}
y={(d) => d.y}
/>
))}
<Drag
width={width}
height={height}
resetOnStart
onDragStart={({ x = 0, y = 0 }) => {
// add the new line with the starting point
setLines((currLines) => [...currLines, [{ x, y }]]);
}}
onDragMove={({ x = 0, y = 0, dx, dy }) => {
// add the new point to the current line
setLines((currLines) => {
const nextLines = [...currLines];
const newPoint = { x: x + dx, y: y + dy };
const lastIndex = nextLines.length - 1;
nextLines[lastIndex] = [
...(nextLines[lastIndex] || []),
newPoint
];
return nextLines;
});
}}
>
{({
x = 0,
y = 0,
dx,
dy,
isDragging,
dragStart,
dragEnd,
dragMove
}) => (
<g>
{/* decorate the currently drawing line */}
{isDragging && (
<g>
<rect
fill="white"
width={8}
height={8}
x={x + dx - 4}
y={y + dy - 4}
pointerEvents="none"
/>
<circle
cx={x}
cy={y}
r={4}
fill="transparent"
stroke="white"
pointerEvents="none"
/>
</g>
)}
{/* create the drawing area */}
<rect
fill="transparent"
width={width}
height={height}
onMouseDown={dragStart}
onMouseUp={dragEnd}
onMouseMove={dragMove}
onTouchStart={dragStart}
onTouchEnd={dragEnd}
onTouchMove={dragMove}
/>
</g>
)}
</Drag>
</svg>
<div className="deets">
<div>
Based on Mike Bostock's{' '}
<a href="https://bl.ocks.org/mbostock/f705fc55e6f26df29354">
Line Drawing
</a>
</div>
</div>
<style jsx>{`
.DragII {
display: flex;
flex-direction: column;
user-select: none;
}
svg {
margin: 1rem 0;
cursor: crosshair;
}
.deets {
display: flex;
flex-direction: row;
font-size: 12px;
}
.deets > div {
margin: 0.25rem;
}
`}</style>
</div>
);
}
The end
If you're curious to learn more you should head over to their GitHub or documentation page.