react-speedometer
Version:
Cool speedometer for React
342 lines (281 loc) ⢠9.1 kB
Markdown
# Cool Speedometer š
If you are tired of all those boring speedometers for react, have a look at this one. This is different. This is cool.


ā
Flexible
ā
0 dependencies
ā
Performant
ā
Support for negative numbers
ā
Made out of SVG
ā
More customization than you'll use
ā
Cool š
Install it for free:
```bash
npm i react-speedometer
```
# Usage

```jsx
import Speedometer, {
Background,
Arc,
Needle,
Progress,
Marks,
Indicator,
} from 'react-speedometer';
// a few lines later ...
<Speedometer
value={128}
fontFamily='squada-one'
>
<Background />
<Arc/>
<Needle/>
<Progress/>
<Marks/>
<Indicator/>
</Speedometer>
```
That's it, you can play around changing some of the components inside `<Speedometer>`. Take in mind the order of them matters: `<Background>` is first because it is meant to be behind all other components.
#### sizing
By default, the size of the component is `250`. You can resize it by passing a different `width`. You can also change the `height`, if you need a proportion other than 1:1.
---
# Examples
### Playing with angle

```jsx
<Speedometer
value={54}
max={80}
angle={160}
fontFamily='squada-one'
>
<Background angle={180} />
<Arc/>
<Needle/>
<Progress/>
<Marks/>
<Indicator>
{(value, textProps) => (
<Text
{...textProps}
fontSize={60}
fill="#555"
x={250 / 2}
y={210}
textAnchor="middle"
fontFamily='squada-one'
>
{value}k/m
</Text>
)}
</Indicator>
</Speedometer>
```
### Rotated
Changing `rotation`, `step`, the looking of `<Needle/>`, and adding `<DangerPath/>`:

```jsx
<Speedometer
value={5}
max={11}
fontFamily='squada-one'
>
<Background />
<Arc arcWidth={4} />
<Needle
baseOffset={40}
circleRadius={30}
/>
<DangerPath/>
<Progress arcWidth={10} />
<Marks step={1} />
</Speedometer>
```
### If speed is not your thing
#### Circular progress
<img src="./assets/progress.png" width="200" height="200" />
[See code](https://github.com/lucassaid/react-speedometer/blob/master/examples/CircularProgress.jsx)
#### Thermostat
<img src="./assets/thermostat.png" width="200" height="200" />
[See code](https://github.com/lucassaid/react-speedometer/blob/master/examples/Thermostat.jsx)
---
# God mode
When I said "more customization than you'll use", I meant it.
### Custom marks
Pass a function as children to render your own marks. This function receives:
- **coordinates**
Coordinates of the current line: `{ x1, y1, x2, y2 }`. Either pass them to a `<Line>` component, or use them to create whatever you like, as long as it is made of SVG.
- **textProps**
Coordinates and rotation for the text: `{ x, y, transform }`. It is recommended you apply this object to a `<Text>` element.
- **value**
The value of this mark.
```jsx
import { Line } from 'react-native-svg'
// later ...
<Marks step={5}>
{(mark, i) => (
<G key={i}>
<Line
{...mark.coordinates}
// any other prop here, except x1, y1, x2, and y2
/>
{(i % 2 == 0) && (
// only show the number if the mark is even
<Text
{...mark.textProps}
// any other prop here, except x, y, and transform
>
{mark.value}
</Text>
)}
</G>
)}
</Marks>
```
### Custom needle
Pass a function as children to make a custom needle. It will rotate automatically.
```jsx
<Speedometer width={width}>
<Needle>
{() => {
// you might need the center of the circle
// to place the needle correctly
const center = width / 2
return (
// some magic SVG here
)
}}
</Needle>
</Speedometer>
```
### Custom indicator
Pass a function as children to make a custom indicator. You can use this to place the indicator in the center of the circle:
```jsx
<Speedometer width={width}>
<Indicator>
{(value, textProps) => (
<Text
{...textProps} // textProps has the "transform" property only
fontSize={40}
x={width / 2}
y={width / 2 + 10}
textAnchor="middle"
alignmentBaseline="middle"
>
{value}
</Text>
)}
</Indicator>
</Speedometer>
```
### useSpeedometerContext
You can achieve virtually anything you need by adding a component that uses this hook and returns SVG:
```jsx
const MyCustomSVG = () => {
const {
currentFillAngle,
radius,
rotation,
min,
max,
angle,
lineCap,
accentColor,
fontFamily,
value,
} = useSpeedometerContext();
return (
// some magic SVG here
)
}
const App = () => {
return (
<Speedometer>
<Background />
<Needle />
<MyCustomSVG />
</Speedometer>
)
}
```
### Just SVG
It is possible to wrap any component inside a `<G>` tag and add more vectors:
```jsx
<Speedometer>
<G opacity={0.4}>
<Needle/>
</G>
<Line />
<Polygon />
</Speedometer>
```
---
# Properties
| Prop | Default | Type | Description
| :---- | :------ | :--- | :---------
| width | 250 | number | Width of the component |
| height | same as width | number | Height of the component |
| angle | 250 | number | Angle of the speedometer in degrees |
| rotation | | number | By default, the rotation is computed with the given `angle` to keep the marks symmetrical. If you want to change the rotation (like [this example](#rotated)) take in mind that "0" is at the top of the circle. |
| value | 0 | number | Current value of the speedometer, this is what you typically change dynamically |
| min | 0 | number | Minimum value, can be a negative number |
| max | 180 | number | Max value |
| lineCap | 'butt' | string | Line terminations, can be `butt`, `line`, or `square` |
| accentColor | '#00e0ff' | string | Accent color. Used by default for the progress bar, and the circle of the needle. |
| fontFamily | 'helvetica' | string | Font to use in the indicator and the marks. You need to configure in your project the font you want to use. |
### Background
| Prop | Default | Type | Description
| :---- | :------ | :--- | :---------
| angle | 360 | number | A lower angle will result in a shorter circle |
| color | 'black' | string | Color of background |
| opacity | 0.5 | number | Opacity of background |
### Arc
| Prop | Default | Type | Description
| :---- | :------ | :--- | :---------
| color | 'black | Color of the arc behind the progress |
| opacity | 0.3 | Opacity of the arc behind the progress |
| arcWidth | 4 | number | Width of the arc behind the progress |
| lineCap | Same as global `lineCap` | string | Line terminations, can be `butt`, `line`, or `square` |
### Needle
| Prop | Default | Type | Description
| :---- | :------ | :--- | :---------
| offset | 25 | number | Distance from the border of the circle. A higher number will make the needle shorter. |
| baseWidth | 6 | number | Width of the base of the needle |
| baseOffset | 18 | number | Distance of the base from the center of the circle |
| color | 'white' | string | Color of the needle |
| circleRadius | 15 | number | Radius of the circle at the base of the needle |
| circleColor | Same as global `accentColor` | string | Color of the circle at the base of the needle |
### DangerPath
| Prop | Default | Type | Description
| :---- | :------ | :--- | :---------
| color | '#FF3333' | string | Color of the danger path |
| angle | 50 | number | Angle of the danger path, from the right |
| arcWidth | 4 | string | Width of the danger path |
| lineCap | same as global `lineCap` | string | Line terminations, can be `butt`, `line`, or `square` |
| offset | 6 | number | Distance from the border of the circle |
### Progress
| Prop | Default | Type | Description
| :---- | :------ | :--- | :---------
| color | Same as global `accentColor` | string | Color of the progress bar |
| arcWidth | 5 | number | Width of the progress bar |
| lineCap | Same as global `lineCap` | string | Line terminations, can be `butt`, `line`, or `square` |
### Marks
| Prop | Default | Type | Description
| :---- | :------ | :--- | :---------
| step | 10 | number | Times `max` will be divided in, to show the line marks |
| lineCap | 'butt' | string | Line terminations, can be `butt`, `line`, or `square` |
| lineColor | 'white' | string | Color of lines |
| lineOpacity | 1 | number | Opacity of lines |
| numbersRadius | 17 | number | Distance from the border of the circle |
| fontSize | 18 | number | Font size of the numbers |
| lineSize | 12 | number | Large of the lines |
### Indicator
| Prop | Default | Type | Description
| :---- | :------ | :--- | :---------
| suffix | | string | Text after the value |
| fontSize | 45 | number | Font size of the indicator |
| color | 'white' | Text color of the indicator |
| fontFamily | Same as global `fontFamily` | number | Font family of the indicator |