Skip to content

Instantly share code, notes, and snippets.

@gnchrv
Last active September 26, 2023 08:07
Show Gist options
  • Save gnchrv/a20b14412bd07fd0c9ac66c151257b24 to your computer and use it in GitHub Desktop.
Save gnchrv/a20b14412bd07fd0c9ac66c151257b24 to your computer and use it in GitHub Desktop.
import { useRef, useState, useEffect } from 'react'
import Slider from './components/slider/slider'
import * as Plot from '@observablehq/plot'
function App() {
const [points, setPoints] = useState(10)
const [max, setMax] = useState(10)
const plotContainer = useRef<HTMLDivElement>(null)
useEffect(() => {
const x2 = new Array(points)
.fill(0)
.map((_, i) => ({
x: i === 0 ? 0 : max / points * (i + 1),
y: Math.pow(i === 0 ? 0 : max / points * (i + 1), 2),
name: 'square'
}))
const x4 = new Array(points)
.fill(0)
.map((_, i) => ({
x: i === 0 ? 0 : max / points * (i + 1),
y: Math.pow(i === 0 ? 0 : max / points * (i + 1), 4),
name: 'quad'
}))
const barChart = Plot.plot({
marks: [
Plot.line(x2, {
x: 'x',
y: 'y',
stroke: 'name',
marker: true,
margin: 60,
strokeWidth: 3,
}),
Plot.line(x4, {
x: 'x',
y: 'y',
stroke: 'name',
marker: true,
margin: 60,
strokeWidth: 3
}),
],
y: {
grid: true,
domain: [0, 10]
},
x: {
grid: true,
domain: [0, max]
},
height: 500,
aspectRatio: 1
})
barChart.setAttribute('font-size', '.8rem')
plotContainer.current?.append(barChart)
return () => barChart.remove()
}, [points, max])
return <section
style={{
display: 'flex',
flexDirection: 'column',
gap: '2rem',
alignItems: 'center',
width: '100%',
maxWidth: '25rem',
margin: '1rem auto'
}}
>
<Slider
value={points}
min={2}
max={100}
title='Количество точек'
style={{ width: '20rem' }}
onChange={event => { setPoints(+event.target.value) }}
/>
<Slider
value={max}
min={0}
max={10}
step={0.1}
title='Правая граница'
style={{ width: '20rem' }}
onChange={event => { setMax(+event.target.value) }}
/>
<div
ref={plotContainer}
style={{
fontSize: '2rem !importants'
}}
></div>
</section>
}
export default App
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.tsx'
import './styles/index.scss'
// Find the root node on the page
const root = document.getElementById('root')!
// Create an app and put it into the root node
ReactDOM.createRoot(root).render(
<React.StrictMode>
<App />
</React.StrictMode>,
)
$track-height: .2rem;
$track-radius: calc($track-height / 2);
$track-color: var(--c-bg-tertiary);
$thumb-height: 1rem;
$thumb-width: calc($thumb-height / 4);
$thumb-color: var(--c-graphic-primary);
.slider {
appearance: none;
outline: none;
width: 100%;
height: $track-height;
border-radius: $track-radius;
background: $track-color;
margin: 1rem 0;
&::-webkit-slider-thumb {
appearance: none;
width: $thumb-width;
height: $thumb-height;
border-radius: calc($thumb-width / 3);
background: $thumb-color;
cursor: pointer;
}
&::-moz-range-thumb {
appearance: none;
width: $thumb-width;
height: $thumb-height;
border-radius: calc($thumb-width / 3);
background: $thumb-color;
cursor: pointer;
}
}
.left {
float: left;
}
.right {
float: right;
}
.title,
.value,
.min,
.max {
color: var(--c-text-primary);
}
.min,
.max {
color: var(--c-text-tertiary);
}
.title {
font-size: .9rem;
}
.min,
.max,
.value {
font-size: .8rem;
font-family: var(--f-family-mono);
}
.group:after {
content: "";
display: table;
clear: both;
}
import styles from './slider.module.scss'
type SliderProps = {
value: number,
min?: number,
max?: number,
step?: number,
title?: string,
style?: React.CSSProperties,
onChange: (event: React.ChangeEvent<HTMLInputElement>) => void
}
export default function Slider(props: SliderProps) {
return <div style={{ ...props.style }}>
{/* A row with the slider name and the current value */}
<section className={styles.group}>
{props.title && <span
className={styles.left + ' ' + styles.title}
>{props.title}</span>
}
<span
className={styles.right + ' ' + styles.value}
>{props.value}</span>
</section>
{/* The slider itself */}
<section>
<input
className={styles.slider}
type="range"
min={props.min}
step={props.step}
max={props.max}
value={props.value}
onChange={props.onChange}
/>
</section>
{/* A row with min and max values of the slider */}
<section className={styles.group}>
{props.min && <span
className={styles.left + ' ' + styles.min}
>{props.min}</span>}
{props.max && <span
className={styles.right + ' ' + styles.max}
>{props.max}</span>}
</section>
</div>
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment