naikus / svg-gauge

Minimalistic, animated SVG gauge. Zero dependencies
MIT License
319 stars 74 forks source link

Add TypeScript types #57

Closed christopher-caldwell closed 2 years ago

christopher-caldwell commented 3 years ago

This library is great, but it was a struggle to get going with TS. Here is what I have so far:

declare module 'svg-gauge' {
  export interface Instance {
    setMaxValue: (max: number) => void
    setValue: (val: number) => void
    setValueAnimated: (val: number, duration: number) => void
    getValue: () => number
  }

  export interface Opts {
    viewBox: string
    /**
     * The angle in degrees to start the dial
     * @default 135
     */
    dialStartAngle?: number
    /** The angle in degrees to end the dial. This MUST be less than dialStartAngle
     * @default 45
     */
    dialEndAngle?: number
    /** The radius of the gauge
     * @default 40
     */
    radius?: number
    /** The minimum value for the gauge. This can be a negative value
     * @default 0
     */
    min?: number
    /** The maximum value for the gauge
     * @default 100
     */
    max?: number
    /** Getter for the label that will be rendered in the center. */
    label?: (currentValue: number) => string
    /** Whether to show the value at the center of the gauge
     * @default true
     */
    showValue?: boolean
    /**     The CSS class of the gauge
     * @default 'gauge'
     */
    gaugeClass?: string
    /** The CSS class of the gauge's dial
     * @default 'dial'
     */
    dialClass?: string
    /** The CSS class of the gauge's fill
     * @default 'value'
     */
    valueDialClass?: string
    /** The CSS class of the gauge's text
     * @default '(value-text)'
     */
    valueClass?: string
    /**
     * An optional function that can return a color for current value
     */
    color?: (currentValue: number) => string
    /** An optional string that specifies the crop region
     * @default '(0 0 100 100)'
     */
    viewBox?: string
  }

  export = (element: HTMLDivElement, props: Partial<Opts>) => Instance
}

Then for usage, the provided React example converted to use these types

import React, { FC, useEffect, useRef } from 'react'
import SvgGauge, { Opts, Instance } from 'svg-gauge'

const defaultOptions: Partial<Opts> = {
  max: 100
}

const Gauge: FC<{ value: number }> = ({ value }) => {
  const gaugeEl = useRef<HTMLDivElement>(null)
  const gaugeRef = useRef<Instance | null>(null)
  useEffect(() => {
    if (!gaugeRef.current) {
      if (!gaugeEl.current) return
      const options = { ...defaultOptions, color: (value) => value < 70 ? 'green' : 'yellow' }
      gaugeRef.current = SvgGauge(gaugeEl.current, options)
      gaugeRef.current?.setValue(1)
    }
    gaugeRef.current?.setValueAnimated(value, 1)
  }, [value])

  return (
    <div style={{ height: '500px', width: '500px' }}>
      <div ref={gaugeEl} className='gauge-container' style={{ position: 'relative' }}>
        <span style={{ position: 'absolute', left: '45%', bottom: '70%' }}>km/hr</span>
      </div>
    </div>
  )
}

I'm rather unfamiliar with the library, so i could be way off. This is just what I have so far and is working for my simplistic use case.

naikus commented 3 years ago

Hi @christopher-caldwell can you make a pull request with this?

christopher-caldwell commented 3 years ago

@naikus Sure!

christopher-caldwell commented 3 years ago

https://github.com/naikus/svg-gauge/pull/58

christopher-caldwell commented 3 years ago

Bump

naikus commented 3 years ago

Done