Visx - это библиотека, которая позволяет нам легко добавлять графику в наше приложение React.
В этой статье мы рассмотрим, как использовать его для добавления кривых с сегментами, имеющими собственные стили, в наше приложение React.
Установить необходимые пакеты
Пришлось установить несколько модулей.
Для начала запускаем:
npm i @visx/curve @visx/gradient @visx/responsive @visx/scale @visx/shape
для установки пакетов.
Создайте многостильную линию
Мы можем создать диаграмму, добавив элементы, предоставленные модулями.
Чтобы добавить строку, мы пишем:
import React, { useMemo } from "react"; import { scaleLinear } from "@visx/scale"; import { curveCardinal } from "@visx/curve"; import { LinePath, SplitLinePath } from "@visx/shape"; import { LinearGradient } from "@visx/gradient"; const getX = (d) => d.x; const getY = (d) => d.y; const background = "#045275"; const backgroundLight = "#089099"; const foreground = "#b7e6a5"; function generateSinPoints({ width, height, numberOfWaves = 10, pointsPerWave = 10 }) { const waveLength = width / numberOfWaves; const distanceBetweenPoints = waveLength / pointsPerWave; const sinPoints = []; for (let waveIndex = 0; waveIndex <= numberOfWaves; waveIndex += 1) { const waveDistFromStart = waveIndex * waveLength; for (let pointIndex = 0; pointIndex <= pointsPerWave; pointIndex += 1) { const waveXFraction = pointIndex / pointsPerWave; const waveX = pointIndex * distanceBetweenPoints; const globalX = waveDistFromStart + waveX; const globalXFraction = (width - globalX) / width; const waveHeight = Math.min(globalXFraction, 1 - globalXFraction) * height; sinPoints.push({ x: globalX, y: waveHeight * Math.sin(waveXFraction * (2 * Math.PI)) }); } } return sinPoints; } function Example({ width, height, numberOfWaves = 10, pointsPerWave = 100, numberOfSegments = 8 }) { const data = useMemo( () => generateSinPoints({ width, height, numberOfWaves, pointsPerWave }), [width, height, numberOfWaves, pointsPerWave] ); const dividedData = useMemo(() => { const segmentLength = Math.floor(data.length / numberOfSegments); return new Array(numberOfSegments) .fill(null) .map((_, i) => data.slice(i * segmentLength, (i + 1) * segmentLength)); }, [numberOfSegments, data]); const getScaledX = useMemo(() => { const xScale = scaleLinear({ range: [0, width], domain: [0, width] }); return (d) => xScale(getX(d)) ?? 0; }, [width]); const getScaledY = useMemo(() => { const yScale = scaleLinear({ range: [0, height], domain: [height, 0] }); return (d) => yScale(getY(d)) ?? 0; }, [height]); return width < 10 ? null : ( <div> <svg width={width} height={height}> <LinearGradient id="visx-shape-splitlinepath-gradient" from={background} to={backgroundLight} fromOpacity={0.8} toOpacity={0.8} /> <rect x={0} y={0} width={width} height={height} fill="url(#visx-shape-splitlinepath-gradient)" rx={14} /> <g transform={`rotate(${0})translate(${-0}, ${-height * 0.5})`}> <LinePath data={data} x={getScaledX} y={getScaledY} strokeWidth={8} stroke="#fff" strokeOpacity={0.15} curve={curveCardinal} /> <SplitLinePath segments={dividedData} x={getScaledX} y={getScaledY} curve={curveCardinal} styles={[ { stroke: foreground, strokeWidth: 3 }, { stroke: "#fff", strokeWidth: 2, strokeDasharray: "9,5" }, { stroke: background, strokeWidth: 2 } ]} > {({ segment, styles, index }) => index === numberOfSegments - 1 || index === 2 ? ( segment.map(({ x, y }, i) => i % 8 === 0 ? ( <circle key={i} cx={x} cy={y} r={10 * (i / segment.length)} stroke={styles?.stroke} fill="transparent" strokeWidth={1} /> ) : null ) ) : ( <LinePath data={segment} x={(d) => d.x || 0} y={(d) => d.y || 0} {...styles} /> ) } </SplitLinePath> </g> </svg> </div> ); } export default function App() { return ( <div className="App"> <Example width={500} height={300} /> </div> ); }
Мы добавляем функции getX
и getY
, чтобы получить данные для осей x и y.
background
- один из цветов градиента фона.
backgroundLight
имеет более светлый цвет фонового градиента.
foreground
имеет один из цветов линии.
Мы генерируем точки для линии с помощью функции generateSinPoints
.
globalX
имеет координаты x синусоиды.
И мы используем метод Math.sin
для создания значения оси y.
В компоненте Example
мы визуализируем линию в различных стилях.
Делим линию на сегменты переменной dividedData
.
Это делается путем создания массива значений и разделения значений, созданных из generateSinPoints
, на slice
.
Затем мы создаем шкалы для графика с помощью переменных getScaledX
и getScaledY
.
Мы создаем их с помощью функции scaleLinear
, так как все в линейном масштабе.
Затем мы визуализируем левый отрезок линии с помощью компонента LinePath
.
И мы используем компонент SplitLinePath
для рендеринга оставшихся сегментов.
Мы получаем стили из опоры styles
и визуализируем их стили с помощью компонента LineSegment
, который мы возвращаем в опоре рендеринга SplitLinePath
.
Заключение
Мы можем создать линию из нескольких сегментов с их собственными стилями в нашем приложении React с библиотекой Visx.
Понравилась эта статья? Если да, то получите больше похожего контента, подписавшись на наш канал YouTube!
Больше контента на plainenglish.io