Giter VIP home page Giter VIP logo

use-gauge's Introduction

use-gauge

npm version bundlesize

A headless React hook for building gauge charts. You bring the styles, we bring the math that powers your chart!

Screen Shot 2022-02-08 at 11 05 36 PM

Code for the examples above ๐Ÿ‘† https://i19w7.csb.app/

Installation

yarn add use-gauge

Usage

๐Ÿšจ Beware that this API is very much in flux! Breaking changes will occur, but I'll update these docs and the Codesandbox accordingly ๐Ÿšจ

In your React project, import the useGauge hook and invoke it with the following parameters.

const {
  ticks,
  valueToAngle,
  angleToValue,
  getTickProps,
  getLabelProps,
  getArcProps,
  getNeedleProps,
  getSVGProps,
} = useGauge({
  startAngle: 90, // The bottom of the gauge is considered 90 degrees, so this means 90 degrees FROM 90, so 180.
  endAngle: 270, // And this means 270 degrees FROM 90, so 360.
  numTicks, // the number of ticks to display between the min and max values
  diameter, // diameter of the gauge itself
  domain: [minValue, maxValue], // Min and max values for your gauge. *Please* use a min that's smaller than the max :)
});

If you want to skip ahead and see a fully baked implementation of this hook, check out the example playground.

Otherwise, here's a brief explanation of how these returned values work.

getSVGProps

Please be sure to apply these props to your SVG element, as it's responsible for programatically updating the height, width, and viewBox of the element as a function of the diameter you provide.

<svg {...getSVGProps()}></svg>

ticks, getTickProps, getLabelProps, and angleToValue

ticks is an array of evenly spaced angles (represented as numbers) that's calculated from the numTicks, startAngle, and endAngle argument.

You can create visual tick marks on the SVG by mapping over this array and passing each angle (along with a length argument) to the getTickProps function accordingly.

Additionally, you can render text labels for tick mark by invoking the getLabelProps on the given angle (along wiht an offset argument that determines how far the label sits from the tick).

Note that you'll need to convert the given angle to its "value" counterpart (as minValue and maxValue are the domain of our dataset) by invoking the angleToValue function with the given angle as an argument.

{
  ticks.map((angle) => {
    return (
      <React.Fragment key={`tick-group-${angle}`}>
        <line
          stroke={tickColor}
          {...getTickProps({ angle, length: tickLength })}
        />
        <text
          className="text-sm fill-gray-500 font-medium"
          {...getLabelProps({ angle, offset: 20 })}
        >
          {angleToValue(angle)}
        </text>
      </React.Fragment>
    );
  });
}

getArcProps

This function allows you to render arcs of arbitrary length, as expressed by a start angle and end angle. A common use-case might be to have two arcs: one as a "background", and another that represents the progress of the gauge.

You can calculate progress in this scenario by converting your numerical value to its angle counterpart with the valueToAngle function.

// Background
<path
  {...getArcProps({ offset, startAngle: 90, endAngle: 270 })}
  className="stroke-gray-100"
  strokeLinecap="round"
  strokeWidth={24}
/>

// Progress
<path
{...getArcProps({
  offset,
  startAngle,
  endAngle: valueToAngle(value),
})}
className="stroke-blue-600"
strokeLinecap="round"
strokeWidth={24}
/>

getNeedleProps

Last but not least, this function helps you draw a needle shape on your gauge. Specifically, it returns the bits you need to draw: A) the "tip" of the needle (i.e., the small circle at the top), B) the "base" of the needle (i.e., the bigger circle at the bottom), and C) the "body" of the needle (i.e., the polyline that connects these two circles).

Warning: this API is janky. There's got to be a better way of handling this, but again, this is what worked for my initial use case ๐Ÿคท๐Ÿปโ€โ™‚๏ธ

const { tip, base, points } = getNeedleProps({
  value,
  baseRadius: 12,
  tipRadius: 8,
});

<g id="needle">
  <circle className="fill-gray-300" {...base} r={24} />
  <circle fill={needleColor} {...base} />
  <circle fill={needleColor} {...tip} />
  <polyline fill={needleColor} points={points} />
  <circle className="fill-white" {...base} r={4} />
</g>;

Local Development

From the project root, run yarn start. This will run tsdx in watch mode, and will re-compile the code every time you save.

In a different terminal window, cd into the /example directory and run yarn start. This will boot up Parcel and open a web server at http://localhost:1234. All of your changes to the hook source code will (eventually) propagate to Parcel's hot-reloading server.

use-gauge's People

Contributors

mattrothenberg avatar satnamsvirdi avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

use-gauge's Issues

Add offset to needle tip

I'd like to request you a feature to add offset to needle.

Background

I'm using a gauge like component in one of our app and your hook was a perfect choice for that use case. But our designer suggested to add some spacing between the needle tip and upon checking the readme and the code I've found that there were no options to do this.

Solution

As as solution, I've added a PR to add the missing functionality, so the others can benefit from it as well. You can take a look at the open PR here.

Feel free to share your thoughts/suggestions, if any.

Lastly, thank you for this amazing hook!

How to add the actual gauge value?

I see from your screenshots that you've added the actual value below the gauge. But in the code there is no such label or svg <text> element.

How would I go about adding one?

Warning: A props object containing a "key" prop is being spread into JSX

hi!
I have issue in NextJS 13
this line:
{...gauge.getTickProps({ angle, length: showText ? 12 : 6 })}
in arced.tsx

this error:
Warning: A props object containing a "key" prop is being spread into JSX:
let props = {key: someKey, className: ..., strokeWidth: ..., x1: ..., x2: ..., y1: ..., y2: ...};
<line {...props} />
React keys must be passed directly to JSX without using spread:
let props = {className: ..., strokeWidth: ..., x1: ..., x2: ..., y1: ..., y2: ...};
<line key={someKey} {...props} />

Hard time using ticks and certain values for label

Hey there again!

I'm working on a gauge that displays solar wind from 200 to 1000. I would love to be able to display 200, 300, 400, 500, 600, 700, 800, 900 and 1000 as ticks. But no matter what numTicks value I use, I always get result like this:

image

Is there any good solution to this? Would I need to adjust the startAngle and endAngle?

How to add gradient to arch?

My understanding is that this hook makes it so that you can design/customize your svg gauge however you want - not as user friendly but very flexible.

I checked all the code and examples but couldn't find an example where the arch would be of a gradient instead of a single color.

How would you go about doing this in the best possible way? I suck at SVG bug but instead of doing fill="some color hex" I would use some sort of gradient attribute, e.g. gradient="fromvalue to value"?

feature: Rotate the needle with CSS transform rotate to allow animation

I am working on a gauge that should move the needle smoothly. I was wondering if it would make more sense to use CSS transform to rotate the needle. That way one could enable transition on the transform for smooth rotation.

My current solution:

        <g
          id="needle"
          className={styles.needle}
          style={{
            transform: `rotate(${gauge.valueToAngle(value) - 90}deg)`,
          }}
        >
          <circle className={styles.needleBase} {...needle.base} r={12} />
          <circle className={styles.needleBase} {...needle.base} />
          <circle className={styles.needleTip} {...needle.tip} />
          <polyline className={styles.needlePoints} points={needle.points} />
          <circle className={styles.needleBase} {...needle.base} r={4} />
        </g>

CSS:

  .needle {
    transition: 0.2s ease-in-out;
  }

Then inside getNeedleProps I just hard-code the angle to 0.

For my use case this works beautifully.

Issue with certain numbers

Hey there. First of all, thank you for an excellent gauge hook for React, really appreciate it!

I've run into one issue where I'm showing solar KP index on a gauge. I have values ranging from 0 to 9. When the value is 8, the needle doesn't seem to point at the correct value.

image

Values such as 0, 5 and 9 seem to work fine.

Any clue what the issue could be? I've tried digging into the source code, removed all cases of Math.floor and Math.round, it looks a bit better but still obviously off.

Thank you.

enhancement: different needle shapes

Currently, there's only one needle shape โ€“ this weird thing where we connect a smaller circle ("tip") to a larger circle ("base") and fill in the rest with a polyline. It'd be cool if users could provide their own needle shape, be it an arrow, a straight line, etc.

Screen Shot 2022-02-09 at 8 41 23 AM

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.