recharts#AreaChart TypeScript Examples

The following examples show how to use recharts#AreaChart. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: index.tsx    From vvs-ui with GNU General Public License v3.0 5 votes vote down vote up
LineChart = ({ data, setHoverValue, setHoverDate }: LineChartProps) => {
  const { theme } = useTheme()
  if (!data || data.length === 0) {
    return <LineChartLoader />
  }
  return (
    <ResponsiveContainer>
      <AreaChart
        data={data}
        width={300}
        height={308}
        margin={{
          top: 5,
          right: 15,
          left: 0,
          bottom: 5,
        }}
        onMouseLeave={() => {
          if (setHoverDate) setHoverDate(undefined)
          if (setHoverValue) setHoverValue(undefined)
        }}
      >
        <XAxis
          dataKey="time"
          axisLine={false}
          tickLine={false}
          tickFormatter={(time) => format(time, 'dd')}
          minTickGap={10}
        />
        <YAxis
          dataKey="value"
          tickCount={6}
          scale="linear"
          axisLine={false}
          tickLine={false}
          fontSize="12px"
          tickFormatter={(val) => `$${formatAmount(val)}`}
          orientation="right"
          tick={{ dx: 10, fill: theme.colors.textSubtle }}
        />
        <Tooltip
          cursor={{ stroke: theme.colors.primary }}
          contentStyle={{ display: 'none' }}
          formatter={(tooltipValue, name, props) => (
            <HoverUpdater payload={props.payload} setHoverValue={setHoverValue} setHoverDate={setHoverDate} />
          )}
        />
        <Area
          dataKey="value"
          type="monotone"
          stroke={theme.colors.primary}
          fill={theme.colors.lightBlue}
          strokeWidth={2}
        />
      </AreaChart>
    </ResponsiveContainer>
  )
}
Example #2
Source File: Question.tsx    From project-loved-web with MIT License 5 votes vote down vote up
function ComparingChart({ answers, comparingStatistic }: ComparingChartProps) {
  const intl = useIntl();
  const colors = useColors();

  const xAxisProps: XAxisProps = {
    dataKey: 'statistic',
    interval: 'preserveStartEnd',
    stroke: colors.content,
    tick: { fill: colors.content },
    tickLine: { stroke: colors.content },
  };

  if (comparingStatistic === 'rank') {
    xAxisProps.domain = ['dataMin', 'dataMax'];
    xAxisProps.scale = 'log';
    xAxisProps.tickFormatter = (value) => intl.formatNumber(value);
    xAxisProps.type = 'number';
  }

  return (
    <AreaChart data={answers} width={700} height={175}>
      <defs>
        <linearGradient id='answerColor' x1='0' y1='0' x2='0' y2='1'>
          <stop offset='0%' stopColor={colors['rating-2']} stopOpacity={0.9} />
          <stop offset='20%' stopColor={colors['rating-1']} stopOpacity={0.8} />
          <stop offset='40%' stopColor={colors['rating-0']} stopOpacity={0.7} />
          <stop offset='60%' stopColor={colors['rating--1']} stopOpacity={0.6} />
          <stop offset='80%' stopColor={colors['rating--2']} stopOpacity={0.5} />
          <stop offset='100%' stopColor={colors['rating--2']} stopOpacity={0} />
        </linearGradient>
      </defs>
      <XAxis {...xAxisProps} />
      <YAxis dataKey='average' domain={[0, 5]} hide />
      <Area
        type='monotone'
        dataKey='average'
        stroke={colors.content}
        fillOpacity={1}
        fill='url(#answerColor)'
      />
    </AreaChart>
  );
}
Example #3
Source File: index.tsx    From glide-frontend with GNU General Public License v3.0 5 votes vote down vote up
LineChart = ({ data, setHoverValue, setHoverDate }: LineChartProps) => {
  const { theme } = useTheme()
  if (!data || data.length === 0) {
    return <LineChartLoader />
  }
  return (
    <ResponsiveContainer>
      <AreaChart
        data={data}
        width={300}
        height={308}
        margin={{
          top: 5,
          right: 15,
          left: 0,
          bottom: 5,
        }}
        onMouseLeave={() => {
          if (setHoverDate) setHoverDate(undefined)
          if (setHoverValue) setHoverValue(undefined)
        }}
      >
        <defs>
          <linearGradient id="gradient" x1="0" y1="0" x2="0" y2="1">
            <stop offset="5%" stopColor={theme.colors.inputSecondary} stopOpacity={0.5} />
            <stop offset="100%" stopColor={theme.colors.secondary} stopOpacity={0} />
          </linearGradient>
        </defs>
        <XAxis
          dataKey="time"
          axisLine={false}
          tickLine={false}
          tickFormatter={(time) => format(time, 'dd')}
          minTickGap={10}
        />
        <YAxis
          dataKey="value"
          tickCount={6}
          scale="linear"
          axisLine={false}
          tickLine={false}
          fontSize="12px"
          tickFormatter={(val) => `$${formatAmount(val)}`}
          orientation="right"
          tick={{ dx: 10, fill: theme.colors.textSubtle }}
        />
        <Tooltip
          cursor={{ stroke: theme.colors.secondary }}
          contentStyle={{ display: 'none' }}
          formatter={(tooltipValue, name, props) => (
            <HoverUpdater payload={props.payload} setHoverValue={setHoverValue} setHoverDate={setHoverDate} />
          )}
        />
        <Area dataKey="value" type="monotone" stroke={theme.colors.secondary} fill="url(#gradient)" strokeWidth={2} />
      </AreaChart>
    </ResponsiveContainer>
  )
}
Example #4
Source File: ChartDetailsSinglestat.tsx    From kubenav with MIT License 5 votes vote down vote up
ChartDetailsSinglestat: React.FunctionComponent<IChartDetailsSinglestatProps> = ({
  unit,
  results,
}: IChartDetailsSinglestatProps) => {
  const context = useContext<IContext>(AppContext);

  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  const series: any = [];

  for (let i = 0; i < results.length; i++) {
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    const data: any = [];
    for (let j = 0; j < results[i].values.length; j++) {
      data.push({
        time: results[i].values[j][0],
        value: parseFloat(results[i].values[j][1]),
      });
    }
    series.push({ name: results[i].label, data: data });
  }

  return (
    <IonRow
      style={{
        fontSize: '20px',
        fontWeight: 500,
        color: isDarkMode(context.settings.theme)
          ? isPlatform('ios')
            ? '#ffffff'
            : '#dbdbdb'
          : isPlatform('ios')
          ? '#000000'
          : '#262626',
        height: '100px',
        width: '100%',
      }}
    >
      {series.length > 0 ? (
        <div
          style={{
            margin: 'auto',
            left: 0,
            right: 0,
            top: 40,
            position: 'absolute',
            display: 'flex',
            justifyContent: 'center',
            zIndex: 1000,
          }}
        >
          {series[0].data[series[0].data.length - 1].value.toFixed(2)} {unit ? unit : ''}
        </div>
      ) : null}
      <IonCol style={{ padding: '0px' }}>
        <ResponsiveContainer>
          <AreaChart>
            {series.map((serie, index) => (
              <Area
                key={index}
                dataKey="value"
                // NOTE: https://github.com/recharts/recharts/issues/2487
                // eslint-disable-next-line @typescript-eslint/ban-ts-comment
                // @ts-ignore
                data={serie.data}
                name={serie.name}
                stroke="#326ce5"
                fill="#326ce5"
                fillOpacity={0.2}
              />
            ))}
          </AreaChart>
        </ResponsiveContainer>
      </IonCol>
    </IonRow>
  );
}
Example #5
Source File: OrderChart.tsx    From ra-enterprise-demo with MIT License 5 votes vote down vote up
OrderChart: FC<{ orders?: Order[] }> = ({ orders }) => {
    const translate = useTranslate();
    if (!orders) return null;

    return (
        <Card>
            <CardHeader title={translate('pos.dashboard.month_history')} />
            <CardContent>
                <div style={{ width: '100%', height: 300 }}>
                    <ResponsiveContainer>
                        <AreaChart data={getRevenuePerDay(orders)}>
                            <defs>
                                <linearGradient
                                    id="colorUv"
                                    x1="0"
                                    y1="0"
                                    x2="0"
                                    y2="1"
                                >
                                    <stop
                                        offset="5%"
                                        stopColor="#8884d8"
                                        stopOpacity={0.8}
                                    />
                                    <stop
                                        offset="95%"
                                        stopColor="#8884d8"
                                        stopOpacity={0}
                                    />
                                </linearGradient>
                            </defs>
                            <XAxis
                                dataKey="date"
                                name="Date"
                                type="number"
                                scale="time"
                                domain={[
                                    addDays(aMonthAgo, 1).getTime(),
                                    new Date().getTime(),
                                ]}
                                tickFormatter={dateFormatter}
                            />
                            <YAxis dataKey="total" name="Revenue" unit="€" />
                            <CartesianGrid strokeDasharray="3 3" />
                            <Tooltip
                                cursor={{ strokeDasharray: '3 3' }}
                                formatter={(value): string =>
                                    new Intl.NumberFormat(undefined, {
                                        style: 'currency',
                                        currency: 'USD',
                                    }).format(value as any)
                                }
                                labelFormatter={(label: any): string =>
                                    dateFormatter(label)
                                }
                            />
                            <Area
                                type="monotone"
                                dataKey="total"
                                stroke="#8884d8"
                                strokeWidth={2}
                                fill="url(#colorUv)"
                            />
                        </AreaChart>
                    </ResponsiveContainer>
                </div>
            </CardContent>
        </Card>
    );
}
Example #6
Source File: ClaimGraph.tsx    From mStable-apps with GNU Lesser General Public License v3.0 5 votes vote down vote up
ClaimGraph: FC = () => {
  const rewardsEarned = useRewardsEarned()

  const data = useMemo<DataType[]>(() => {
    return [
      {
        mta: 0,
        ordering: 0,
      },
      {
        mta: rewardsEarned?.rewards ?? 0,
        ordering: 1,
      },
    ]
  }, [rewardsEarned])

  return (
    <Container>
      <ResponsiveContainer width="100%" aspect={1.75}>
        <AreaChart data={data}>
          <defs>
            <linearGradient id="area" x1="0" y1="0" x2="0" y2="1">
              <stop offset="5%" stopColor={Color.blue} stopOpacity={0.5} />
              <stop offset="95%" stopColor={Color.blue} stopOpacity={0} />
            </linearGradient>
          </defs>
          <XAxis
            dataKey="ordering"
            tickFormatter={ordering => (ordering === 0 ? 'Last claim' : 'Now')}
            axisLine={false}
            padding={{ left: 16 }}
            tickLine={false}
          />
          <YAxis tickCount={2} tickFormatter={m => `${m}`} axisLine={false} padding={{ bottom: 16 }} tickLine={false} width={32} />
          <Tooltip
            cursor
            label=""
            labelFormatter={w => (w === 0 ? 'Last claim' : 'Available to claim')}
            formatter={mta => `${(mta as number).toFixed(2)} MTA`}
            separator=""
            contentStyle={{
              fontSize: '14px',
              padding: '8px',
              background: 'rgba(255, 255, 255, 0.8)',
              textAlign: 'right',
              border: 'none',
              borderRadius: '4px',
              color: Color.black,
            }}
            wrapperStyle={{
              top: 0,
              left: 0,
            }}
          />
          <Area type="monotone" name={'Earned: '} dataKey="mta" stroke={Color.blue} strokeWidth={2} fill="url(#area)" />
        </AreaChart>
      </ResponsiveContainer>
    </Container>
  )
}
Example #7
Source File: StakeGraph.tsx    From mStable-apps with GNU Lesser General Public License v3.0 5 votes vote down vote up
StakeGraph: FC = () => {
  const { data: tokenData } = useStakedTokenQuery()
  const weightedTimestamp = tokenData?.stakedToken?.accounts?.[0]?.balance?.weightedTimestamp

  const data = generateData(weightedTimestamp)
  const ticks = removeDuplicatesBy(x => x.multiplier, data).map(v => v.week)

  return (
    <Container>
      <ResponsiveContainer width="100%" aspect={1.75}>
        <AreaChart data={data}>
          <defs>
            <linearGradient id="area" x1="0" y1="0" x2="0" y2="1">
              <stop offset="5%" stopColor={Color.blue} stopOpacity={0.5} />
              <stop offset="95%" stopColor={Color.blue} stopOpacity={0} />
            </linearGradient>
          </defs>
          <XAxis dataKey="week" tickFormatter={w => `${w / WEEK}`} axisLine={false} padding={{ left: 16 }} tickLine={false} ticks={ticks} />
          <YAxis
            domain={['dataMin', 'dataMax']}
            tickCount={4}
            tickFormatter={m => `${m}x`}
            axisLine={false}
            padding={{ bottom: 16 }}
            tickLine={false}
            width={32}
          />
          <Tooltip
            cursor
            labelFormatter={week => `+${(week as number) / WEEK} weeks`}
            formatter={multiplier => multiplier}
            separator=""
            contentStyle={{
              fontSize: '14px',
              padding: '8px',
              background: 'rgba(255, 255, 255, 0.8)',
              textAlign: 'right',
              border: 'none',
              borderRadius: '4px',
              color: Color.black,
            }}
            wrapperStyle={{
              top: 0,
              left: 0,
            }}
          />
          <Area type="stepAfter" name={`multiplier: `} dataKey="multiplier" stroke={Color.blue} strokeWidth={2} fill="url(#area)" />
        </AreaChart>
      </ResponsiveContainer>
    </Container>
  )
}
Example #8
Source File: WithdrawGraph.tsx    From mStable-apps with GNU Lesser General Public License v3.0 5 votes vote down vote up
WithdrawGraph: FC = () => {
  const { data } = useStakedTokenQuery() ?? {}

  const weightedTimestamp = data?.stakedToken?.accounts?.[0]?.balance?.weightedTimestamp ?? nowUnix

  const graphData = useMemo(() => {
    const weeksStaked = (nowUnix - weightedTimestamp) / WEEK
    const data = generateData(weeksStaked)
    const ticks = [...new Set(data.map(d => d.week))]
    return { data, ticks }
  }, [weightedTimestamp])

  return (
    <Container>
      <ResponsiveContainer width="100%" aspect={1.75}>
        <AreaChart data={graphData.data}>
          <defs>
            <linearGradient id="area" x1="0" y1="0" x2="0" y2="1">
              <stop offset="5%" stopColor={Color.blue} stopOpacity={0.5} />
              <stop offset="95%" stopColor={Color.blue} stopOpacity={0} />
            </linearGradient>
          </defs>
          <XAxis
            dataKey="week"
            tickFormatter={w => `${w / WEEK}`}
            axisLine={false}
            padding={{ left: 16 }}
            tickLine={false}
            ticks={graphData.ticks}
          />
          <YAxis tickCount={2} tickFormatter={m => `${m}%`} axisLine={false} padding={{ bottom: 16 }} tickLine={false} width={24} />
          <Tooltip
            cursor
            labelFormatter={week => `+${(week as number) / WEEK} weeks`}
            formatter={fee => `${(fee as number).toFixed(4)}%`}
            separator=""
            contentStyle={{
              fontSize: '14px',
              padding: '8px',
              background: 'rgba(255, 255, 255, 0.8)',
              textAlign: 'right',
              border: 'none',
              borderRadius: '4px',
              color: Color.black,
            }}
            wrapperStyle={{
              top: 0,
              left: 0,
            }}
          />
          <Area type="monotone" name={'Fee: '} dataKey="fee" stroke={Color.blue} strokeWidth={2} fill="url(#area)" />
        </AreaChart>
      </ResponsiveContainer>
    </Container>
  )
}
Example #9
Source File: STResults.tsx    From console with GNU Affero General Public License v3.0 4 votes vote down vote up
STResults = ({ classes, results, start }: ISTResults) => {
  const [jsonView, setJsonView] = useState<boolean>(false);

  const finalRes = results[results.length - 1] || [];

  const getServers: STServer[] = get(finalRes, "GETStats.servers", []) || [];
  const putServers: STServer[] = get(finalRes, "PUTStats.servers", []) || [];

  const getThroughput = get(finalRes, "GETStats.throughputPerSec", 0);
  const getObjects = get(finalRes, "GETStats.objectsPerSec", 0);

  const putThroughput = get(finalRes, "PUTStats.throughputPerSec", 0);
  const putObjects = get(finalRes, "PUTStats.objectsPerSec", 0);

  let statJoin: IndvServerMetric[] = [];

  getServers.forEach((item) => {
    const hostName = item.endpoint;
    const putMetric = putServers.find((item) => item.endpoint === hostName);

    let itemJoin: IndvServerMetric = {
      getUnit: "-",
      getValue: "N/A",
      host: item.endpoint,
      putUnit: "-",
      putValue: "N/A",
    };

    if (item.err && item.err !== "") {
      itemJoin.getError = item.err;
      itemJoin.getUnit = "-";
      itemJoin.getValue = "N/A";
    } else {
      const niceGet = calculateBytes(item.throughputPerSec.toString());

      itemJoin.getUnit = niceGet.unit;
      itemJoin.getValue = niceGet.total.toString();
    }

    if (putMetric) {
      if (putMetric.err && putMetric.err !== "") {
        itemJoin.putError = putMetric.err;
        itemJoin.putUnit = "-";
        itemJoin.putValue = "N/A";
      } else {
        const nicePut = calculateBytes(putMetric.throughputPerSec.toString());

        itemJoin.putUnit = nicePut.unit;
        itemJoin.putValue = nicePut.total.toString();
      }
    }

    statJoin.push(itemJoin);
  });

  const downloadResults = () => {
    const date = new Date();
    let element = document.createElement("a");
    element.setAttribute(
      "href",
      "data:text/plain;charset=utf-8," + JSON.stringify(finalRes)
    );
    element.setAttribute(
      "download",
      `speedtest_results-${date.toISOString()}.log`
    );

    element.style.display = "none";
    document.body.appendChild(element);

    element.click();

    document.body.removeChild(element);
  };

  const toggleJSONView = () => {
    setJsonView(!jsonView);
  };

  const finalResJSON = finalRes ? JSON.stringify(finalRes, null, 4) : "";
  const clnMetrics = cleanMetrics(results);

  return (
    <Fragment>
      <Grid container className={classes.objectGeneral}>
        <Grid item xs={12} md={6} lg={6}>
          <Grid container className={classes.objectGeneral}>
            <Grid item xs={12} md={6} lg={6}>
              <SpeedTestUnit
                icon={
                  <div className={classes.download}>
                    <DownloadStatIcon />
                  </div>
                }
                title={"GET"}
                throughput={getThroughput}
                objects={getObjects}
              />
            </Grid>
            <Grid item xs={12} md={6} lg={6}>
              <SpeedTestUnit
                icon={
                  <div className={classes.upload}>
                    <UploadStatIcon />
                  </div>
                }
                title={"PUT"}
                throughput={putThroughput}
                objects={putObjects}
              />
            </Grid>
          </Grid>
        </Grid>
        <Grid item xs={12} md={6} lg={6}>
          <ResponsiveContainer width="99%">
            <AreaChart data={clnMetrics}>
              <defs>
                <linearGradient id="colorPut" x1="0" y1="0" x2="0" y2="1">
                  <stop offset="0%" stopColor="#2781B0" stopOpacity={0.9} />
                  <stop offset="95%" stopColor="#fff" stopOpacity={0} />
                </linearGradient>
                <linearGradient id="colorGet" x1="0" y1="0" x2="0" y2="1">
                  <stop offset="0%" stopColor="#4CCB92" stopOpacity={0.9} />
                  <stop offset="95%" stopColor="#fff" stopOpacity={0} />
                </linearGradient>
              </defs>

              <CartesianGrid
                strokeDasharray={"0 0"}
                strokeWidth={1}
                strokeOpacity={0.5}
                stroke={"#F1F1F1"}
                vertical={false}
              />

              <Area
                type="monotone"
                dataKey={"get"}
                stroke={"#4CCB92"}
                fill={"url(#colorGet)"}
                fillOpacity={0.3}
                strokeWidth={2}
                dot={false}
              />
              <Area
                type="monotone"
                dataKey={"put"}
                stroke={"#2781B0"}
                fill={"url(#colorPut)"}
                fillOpacity={0.3}
                strokeWidth={2}
                dot={false}
              />
            </AreaChart>
          </ResponsiveContainer>
        </Grid>
      </Grid>
      <br />
      {clnMetrics.length > 1 && (
        <Fragment>
          <Grid container>
            <Grid item xs={12} md={6} className={classes.descriptorLabel}>
              {start ? (
                <Fragment>Preliminar Results:</Fragment>
              ) : (
                <Fragment>
                  {jsonView ? "JSON Results:" : "Detailed Results:"}
                </Fragment>
              )}
            </Grid>
            <Grid item xs={12} md={6} className={classes.actionButtons}>
              {!start && (
                <Fragment>
                  <BoxIconButton
                    aria-label="Download"
                    onClick={downloadResults}
                    size="large"
                  >
                    <DownloadIcon />
                  </BoxIconButton>
                  &nbsp;
                  <BoxIconButton
                    aria-label="Download"
                    onClick={toggleJSONView}
                    size="large"
                  >
                    <JSONIcon />
                  </BoxIconButton>
                </Fragment>
              )}
            </Grid>
          </Grid>
          <Grid container className={classes.resultsContainer}>
            {jsonView ? (
              <Fragment>
                <CodeMirrorWrapper
                  value={finalResJSON}
                  readOnly
                  onBeforeChange={() => {}}
                />
              </Fragment>
            ) : (
              <Fragment>
                <Grid
                  item
                  xs={12}
                  sm={12}
                  md={1}
                  lg={1}
                  className={classes.resultsIcon}
                  alignItems={"flex-end"}
                >
                  <ComputerLineIcon width={45} />
                </Grid>
                <Grid
                  item
                  xs={12}
                  sm={6}
                  md={3}
                  lg={2}
                  className={classes.detailedItem}
                >
                  Nodes:&nbsp;<strong>{finalRes.servers}</strong>
                </Grid>
                <Grid
                  item
                  xs={12}
                  sm={6}
                  md={3}
                  lg={2}
                  className={classes.detailedItem}
                >
                  Drives:&nbsp;<strong>{finalRes.disks}</strong>
                </Grid>
                <Grid
                  item
                  xs={12}
                  sm={6}
                  md={3}
                  lg={2}
                  className={classes.detailedItem}
                >
                  Concurrent:&nbsp;<strong>{finalRes.concurrent}</strong>
                </Grid>
                <Grid
                  item
                  xs={12}
                  sm={12}
                  md={12}
                  lg={5}
                  className={classes.detailedVersion}
                >
                  <span className={classes.versionIcon}>
                    <VersionIcon />
                  </span>{" "}
                  MinIO VERSION&nbsp;<strong>{finalRes.version}</strong>
                </Grid>
                <Grid item xs={12} className={classes.tableOverflow}>
                  <table
                    className={classes.serversTable}
                    cellSpacing={0}
                    cellPadding={0}
                  >
                    <thead>
                      <tr>
                        <th colSpan={2}>Servers</th>
                        <th>GET</th>
                        <th>PUT</th>
                      </tr>
                    </thead>
                    <tbody>
                      {statJoin.map((stats, index) => (
                        <tr key={`storage-${index.toString()}`}>
                          <td className={classes.serverIcon}>
                            <StorageIcon />
                          </td>
                          <td className={classes.serverHost}>{stats.host}</td>
                          {stats.getError && stats.getError !== "" ? (
                            <td>{stats.getError}</td>
                          ) : (
                            <Fragment>
                              <td className={classes.serverValue}>
                                {prettyNumber(parseFloat(stats.getValue))}&nbsp;
                                {stats.getUnit}/s.
                              </td>
                            </Fragment>
                          )}
                          {stats.putError && stats.putError !== "" ? (
                            <td>{stats.putError}</td>
                          ) : (
                            <Fragment>
                              <td className={classes.serverValue}>
                                {prettyNumber(parseFloat(stats.putValue))}&nbsp;
                                {stats.putUnit}/s.
                              </td>
                            </Fragment>
                          )}
                        </tr>
                      ))}
                    </tbody>
                  </table>
                </Grid>
              </Fragment>
            )}
          </Grid>
        </Fragment>
      )}
    </Fragment>
  );
}
Example #10
Source File: LiquidityChart.tsx    From mStable-apps with GNU Lesser General Public License v3.0 4 votes vote down vote up
Chart: FC<{
  aggregateMetrics: {
    type: string
    enabled: boolean
    label: string
    color: string
  }[]
}> = ({ aggregateMetrics }) => {
  const poolAddress = useSelectedFeederPoolAddress()
  const data = useTotalLiquidity(poolAddress)
  const dateFilter = useDateFilter()
  const { metrics } = useMetricsState()
  return (
    <RechartsContainer>
      {data.length < 2 && <NoData>No data yet</NoData>}
      <ResponsiveContainer aspect={2} debounce={1} width="99%">
        <AreaChart margin={{ top: 40, right: 0, bottom: 0, left: 0 }} barCategoryGap={1} data={data.length > 1 ? data : []}>
          <defs>
            {aggregateMetrics.map(({ type, color }) => (
              <linearGradient id={type} key={type} x1="0" y1="0" x2="0" y2="1">
                <stop offset="5%" stopColor={color} stopOpacity={0.5} />
                <stop offset="95%" stopColor={color} stopOpacity={0} />
              </linearGradient>
            ))}
          </defs>
          <XAxis
            dataKey="timestamp"
            axisLine={false}
            xAxisId={0}
            height={0}
            tick={false}
            tickFormatter={timestamp => (timestamp ? format(timestamp * 1000, periodFormatMapping[dateFilter.period]) : '')}
          />
          <YAxis
            type="number"
            orientation="left"
            tickFormatter={toK}
            axisLine={false}
            interval="preserveEnd"
            yAxisId={0}
            tick={false}
            width={0}
          />
          <Tooltip
            cursor
            labelFormatter={timestamp => format((timestamp as number) * 1000, 'yyyy-MM-dd HH:mm')}
            formatter={toK as never}
            separator=""
            contentStyle={{
              fontSize: '14px',
              padding: '8px',
              background: 'rgba(255, 255, 255, 0.8)',
              textAlign: 'right',
              border: 'none',
              borderRadius: '4px',
              color: Color.black,
            }}
            wrapperStyle={{
              top: 0,
              left: 0,
            }}
          />
          {metrics.map(({ color, type, label, enabled }) => (
            <Area
              animationDuration={100}
              key={type}
              type="monotone"
              hide={!enabled}
              dataKey={type}
              name={`${label} `}
              opacity={1}
              dot={false}
              yAxisId={0}
              stroke={color}
              strokeWidth={2}
              fill={`url(#${type})`}
            />
          ))}
        </AreaChart>
      </ResponsiveContainer>
    </RechartsContainer>
  )
}
Example #11
Source File: ClaimGraph.tsx    From mStable-apps with GNU Lesser General Public License v3.0 4 votes vote down vote up
ClaimGraph: FC = () => {
  const rewardStreams = useRewardStreams()

  const chart = useMemo<Chart>(() => {
    if (!rewardStreams) return { maxY: 0, groups: [] }

    // Filter for selected types
    const filtered = rewardStreams.chartData

    // Group into ranges
    const ranges = filtered
      .map(({ t }) => t)
      .reduce<[number, number][]>((prev, x, idx) => {
        if (idx === 0) return [[x, x]]

        const last = prev[prev.length - 1]

        // More than 2 months? Too much of a gap, make a new group
        // Otherwise the chart is hard to read
        // TODO needs more logic here... if I didn't claim for more than that
        //  time since I started earning, it won't show correctly
        // if (x - last[1] > 5184000) {
        //   return [...prev, [x, x]];
        // }

        return [...prev.slice(0, -1), [last[0], x]]
      }, [])

    // Find the max Y value to use a common scale
    const maxY = filtered.reduce(
      // eslint-disable-next-line @typescript-eslint/no-unused-vars
      (prev, { t, ...datum }) => Math.max(prev, ...(Object.values(datum) as number[])),
      0,
    )

    return {
      maxY,
      groups: ranges
        .map(range => {
          const data = filtered.filter(datum => datum.t >= range[0] && datum.t <= range[1])
          const types = Array.from(
            new Set(
              data.reduce<StreamType[]>(
                (prev, datum) => [
                  ...prev,
                  ...Object.entries(datum)
                    .filter(([k, v]) => k !== 't' && v)
                    .map(([k]) => k as unknown as StreamType),
                ],
                [],
              ),
            ),
          )
          return {
            range,
            data,
            types,
          }
        })
        .filter(group => group.data.length > 1),
    }
  }, [rewardStreams])

  if (!rewardStreams) return null

  return (
    <ChartContainer key={chart.groups.length}>
      {chart.groups.map(({ data, types, range }) => (
        <ResponsiveContainer maxHeight={200} aspect={3} key={range[0]}>
          <AreaChart data={data} margin={{ top: 20, left: 0, right: 0, bottom: 0 }}>
            <defs>
              {Object.keys(dataTypes).map(streamType => (
                <linearGradient id={`type-${streamType}`} key={streamType} x1="0" y1="0" x2="0" y2="1">
                  <stop offset="5%" stopColor={rewardsColorMapping[streamType as unknown as StreamType].fill1} />
                  <stop offset="95%" stopColor={rewardsColorMapping[streamType as unknown as StreamType].fill2} />
                </linearGradient>
              ))}
            </defs>
            <Tooltip
              cursor
              labelFormatter={tooltipFormatter}
              formatter={toK as never}
              separator=" "
              contentStyle={{
                fontSize: '14px',
                padding: '8px',
                background: 'rgba(255, 255, 255, 0.8)',
                textAlign: 'right',
                border: 'none',
                borderRadius: '4px',
                color: Color.black,
              }}
              wrapperStyle={{
                top: 0,
                left: 0,
              }}
            />
            <XAxis
              scale="time"
              interval="preserveStartEnd"
              domain={[range[0], 'auto']}
              type="number"
              dataKey="t"
              tickFormatter={xAxisFormatter}
              stroke={Color.greyTransparent}
              padding={{ left: 40, right: 80 }}
            />
            <YAxis
              type="number"
              domain={[0, chart.maxY]}
              orientation="left"
              tickFormatter={toK}
              axisLine={false}
              interval={100}
              // interval="preserveEnd"
              tick={false}
            />
            <ReferenceLine x={rewardStreams?.currentTime} stroke={Color.greyTransparent}>
              <Label position="insideTopRight" value="Unclaimed" fontSize={14} dx={6} dy={-20} />
            </ReferenceLine>
            {rewardStreams?.nextUnlock && (
              <ReferenceLine x={rewardStreams.nextUnlock} stroke={Color.greyTransparent}>
                <Label position="insideTopLeft" value="Next unlock" fontSize={14} dy={-20} dx={-6} />
              </ReferenceLine>
            )}
            {rewardStreams && (
              <ReferenceLine x={rewardStreams.previewStream.start} stroke={Color.greyTransparent}>
                <Label position="insideTopLeft" value="New unlock" fontSize={14} />
              </ReferenceLine>
            )}
            {types.flatMap(streamType =>
              (dataTypes[streamType].subTypes ?? [streamType]).map(subType => (
                <Area
                  key={subType}
                  dataKey={subType}
                  name={dataTypes[subType].label}
                  dot={false}
                  strokeWidth={0}
                  stroke={rewardsColorMapping[subType].point}
                  stackId={1}
                  fill={`url(#type-${subType})`}
                  fillOpacity={1}
                />
              )),
            )}
          </AreaChart>
        </ResponsiveContainer>
      ))}
    </ChartContainer>
  )
}
Example #12
Source File: VolumeChart.tsx    From mStable-apps with GNU Lesser General Public License v3.0 4 votes vote down vote up
Chart: FC = () => {
  const dateFilter = useDateFilter()
  const data = useVolumeMetrics()
  const { metrics } = useMetricsState()

  return (
    <RechartsContainer>
      {data && data.length ? (
        <ResponsiveContainer aspect={2}>
          <AreaChart margin={{ top: 0, right: 16, bottom: 16, left: 16 }} barCategoryGap={1} data={data}>
            <defs>
              {volumeMetrics.map(({ type, color }) => (
                <linearGradient id={type} key={type} x1="0" y1="0" x2="0" y2="1">
                  <stop offset="5%" stopColor={color} stopOpacity={0.5} />
                  <stop offset="95%" stopColor={color} stopOpacity={0} />
                </linearGradient>
              ))}
            </defs>
            <XAxis
              dataKey="timestamp"
              axisLine={false}
              xAxisId={0}
              tickSize={12}
              padding={{ left: 16 }}
              minTickGap={16}
              tickLine
              tickFormatter={timestamp => (timestamp ? format(timestamp * 1000, periodFormatMapping[dateFilter.period]) : '')}
            />
            <YAxis
              type="number"
              orientation="left"
              tickFormatter={toK}
              axisLine={false}
              tickLine
              tickSize={12}
              padding={{ bottom: 16 }}
              interval="preserveEnd"
              minTickGap={8}
              yAxisId={0}
            />
            <YAxis
              type="number"
              hide={!metrics.find(m => m.type === TransactionType.MassetPaidFee && m.enabled)}
              orientation="right"
              tickFormatter={toK}
              axisLine={false}
              tickLine
              tickSize={12}
              name="Fees"
              padding={{ bottom: 16 }}
              interval="preserveEnd"
              minTickGap={8}
              yAxisId={1}
            />
            <Tooltip
              cursor
              labelFormatter={timestamp => format((timestamp as number) * 1000, 'yyyy-MM-dd HH:mm')}
              formatter={toK as never}
              separator=""
              contentStyle={{
                fontSize: '14px',
                padding: '8px',
                background: 'rgba(255, 255, 255, 0.8)',
                textAlign: 'right',
                border: 'none',
                borderRadius: '4px',
                color: Color.black,
              }}
              wrapperStyle={{
                top: 0,
                left: 0,
              }}
            />
            {metrics.map(({ color, type, label, enabled }) => (
              <Area
                isAnimationActive={false}
                key={type}
                type="monotone"
                hide={!enabled}
                dataKey={type}
                name={`${label} `}
                opacity={1}
                dot={false}
                yAxisId={type === TransactionType.MassetPaidFee ? 1 : 0}
                stroke={color}
                strokeWidth={2}
                fill={`url(#${type})`}
              />
            ))}
          </AreaChart>
        </ResponsiveContainer>
      ) : (
        <ThemedSkeleton height={270} />
      )}
    </RechartsContainer>
  )
}
Example #13
Source File: DailyApys.tsx    From mStable-apps with GNU Lesser General Public License v3.0 4 votes vote down vote up
DailyApysChart: FC<{
  shimmerHeight?: number
  tick?: boolean
  marginTop?: number
  aspect?: number
  className?: string
  color?: string
  strokeWidth?: number
  hoverEnabled?: boolean
}> = ({ shimmerHeight = 270, tick, className, marginTop, color, aspect = 2, strokeWidth = 2, hoverEnabled = true }) => {
  const dateFilter = useDateFilter()
  const { DailyApy, UtilisationRate } = useMetrics<MetricTypes>()
  const blockTimes = useBlockTimesForDates(dateFilter.dates)

  const savingsContractState = useSelectedSavingsContractState()
  const dailyApys = useDailyApysForBlockTimes(savingsContractState?.address, blockTimes)

  if (dailyApys.some(value => value.dailyAPY > 1000) || dailyApys.every(value => value.dailyAPY === 0)) {
    return <NoData className={className}>No data available yet</NoData>
  }

  return (
    <RechartsContainer className={className}>
      {dailyApys && dailyApys.length ? (
        <ResponsiveContainer aspect={aspect} debounce={1} width="99%">
          <AreaChart
            margin={tick ? { top: marginTop, right: 16, bottom: 16, left: 16 } : { top: marginTop, right: 0, bottom: 0, left: 0 }}
            barCategoryGap={1}
            data={dailyApys}
          >
            {hoverEnabled && (
              <defs>
                <linearGradient id="utilisationRate" x1="0" y1="0" x2="0" y2="1">
                  <stop offset="5%" stopColor={Color.blackTransparent} stopOpacity={0.5} />
                  <stop offset="95%" stopColor={Color.blackTransparent} stopOpacity={0} />
                </linearGradient>
                <linearGradient id="dailyAPY" x1="0" y1="0" x2="0" y2="1">
                  <stop offset="5%" stopColor={color ?? Color.gold} stopOpacity={0.5} />
                  <stop offset="95%" stopColor={color ?? Color.gold} stopOpacity={0} />
                </linearGradient>
              </defs>
            )}
            <XAxis
              dataKey="timestamp"
              axisLine={false}
              tick={tick}
              xAxisId={0}
              tickSize={12}
              padding={tick ? { left: 16 } : { left: 0 }}
              minTickGap={16}
              tickLine
              height={!tick ? 0 : undefined}
              tickFormatter={(timestamp: number) => (timestamp ? format(timestamp * 1000, periodFormatMapping[dateFilter.period]) : '')}
            />
            <YAxis
              type="number"
              orientation="left"
              tickFormatter={formatApy}
              axisLine={false}
              tick={tick}
              tickLine
              tickSize={12}
              padding={tick ? { bottom: 16 } : { bottom: 0 }}
              interval="preserveEnd"
              minTickGap={8}
              yAxisId={0}
              width={!tick ? 0 : undefined}
            />
            {hoverEnabled && (
              <Tooltip
                cursor
                labelFormatter={timestamp => format((timestamp as number) * 1000, 'yyyy-MM-dd HH:mm')}
                formatter={formatApy as never}
                separator=""
                contentStyle={{
                  fontSize: '14px',
                  padding: '8px',
                  background: 'rgba(255, 255, 255, 0.8)',
                  textAlign: 'right',
                  border: 'none',
                  borderRadius: '4px',
                  color: Color.black,
                }}
                wrapperStyle={{
                  top: 0,
                  left: 0,
                }}
              />
            )}
            <Area
              hide={!UtilisationRate.enabled}
              strokeWidth={strokeWidth}
              type="monotone"
              dataKey="utilisationRate"
              name="SAVE Utilisation "
              opacity={1}
              fill="url(#utilisationRate)"
              yAxisId={0}
              stroke={Color.blackTransparent}
            />
            <Area
              hide={!DailyApy.enabled}
              strokeWidth={strokeWidth}
              type="monotone"
              dataKey="dailyAPY"
              name="Daily APY "
              opacity={1}
              yAxisId={0}
              fill="url(#dailyAPY)"
              stroke={color ?? DailyApy.color}
            />
          </AreaChart>
        </ResponsiveContainer>
      ) : (
        <ThemedSkeleton height={shimmerHeight} />
      )}
    </RechartsContainer>
  )
}
Example #14
Source File: AggregateChart.tsx    From mStable-apps with GNU Lesser General Public License v3.0 4 votes vote down vote up
Chart: FC<{
  aggregateMetrics: {
    type: string
    enabled: boolean
    label: string
    color: string
  }[]
}> = ({ aggregateMetrics }) => {
  const data = useAggregateMetrics()
  const dateFilter = useDateFilter()
  const { metrics } = useMetricsState()
  return (
    <RechartsContainer>
      {data && data.length ? (
        <ResponsiveContainer aspect={2}>
          <AreaChart margin={{ top: 0, right: 16, bottom: 16, left: 16 }} barCategoryGap={1} data={data}>
            <defs>
              {aggregateMetrics.map(({ type, color }) => (
                <linearGradient id={type} key={type} x1="0" y1="0" x2="0" y2="1">
                  <stop offset="5%" stopColor={color} stopOpacity={0.5} />
                  <stop offset="95%" stopColor={color} stopOpacity={0} />
                </linearGradient>
              ))}
            </defs>
            <XAxis
              dataKey="timestamp"
              axisLine={false}
              xAxisId={0}
              tickSize={12}
              padding={{ left: 16 }}
              minTickGap={16}
              tickLine
              tickFormatter={timestamp => (timestamp ? format(timestamp * 1000, periodFormatMapping[dateFilter.period]) : '')}
            />
            <YAxis
              type="number"
              orientation="left"
              tickFormatter={toK}
              axisLine={false}
              tickLine
              tickSize={12}
              padding={{ bottom: 16 }}
              interval="preserveEnd"
              minTickGap={8}
              yAxisId={0}
            />
            <Tooltip
              cursor
              labelFormatter={timestamp => format((timestamp as number) * 1000, 'yyyy-MM-dd HH:mm')}
              formatter={toK as never}
              separator=""
              contentStyle={{
                fontSize: '14px',
                padding: '8px',
                background: 'rgba(255, 255, 255, 0.8)',
                textAlign: 'right',
                border: 'none',
                borderRadius: '4px',
                color: Color.black,
              }}
              wrapperStyle={{
                top: 0,
                left: 0,
              }}
            />
            {metrics.map(({ color, type, label, enabled }) => (
              <Area
                isAnimationActive={false}
                key={type}
                type="monotone"
                hide={!enabled}
                dataKey={type}
                name={`${label} `}
                opacity={1}
                dot={false}
                yAxisId={0}
                stroke={color}
                strokeWidth={2}
                fill={`url(#${type})`}
              />
            ))}
          </AreaChart>
        </ResponsiveContainer>
      ) : (
        <ThemedSkeleton height={270} />
      )}
    </RechartsContainer>
  )
}
Example #15
Source File: ArtistListeningRepartition.tsx    From your_spotify with GNU General Public License v3.0 4 votes vote down vote up
export default function ArtistListeningRepartition({ className }: ArtistListeningRepartitionProps) {
  const { interval } = useSelector(selectRawIntervalDetail);
  const results = useAPI(api.mostListenedArtist, interval.start, interval.end, interval.timesplit);

  const resultsWithCount = useMemo(
    () =>
      results?.map((res) => ({
        _id: res._id,
        artists: res.artists.reduce<Record<string, number>>((acc, curr, idx) => {
          acc[curr.id] = res.counts[idx];
          return acc;
        }, {}),
      })),
    [results],
  );

  const allArtists = useMemo(() => {
    const all: Record<string, Artist> = {};
    results?.forEach((res) => {
      res.artists.forEach((art) => {
        if (!(art.id in all)) {
          all[art.id] = art;
        }
      });
    });
    return all;
  }, [results]);

  const data = useMemo(() => {
    if (!resultsWithCount) {
      return [];
    }
    const d = resultsWithCount.map((curr, idx) => {
      const obj: { x: number; _id: DateId } & any = {
        x: idx,
        _id: curr._id as DateId,
      };
      const total = Object.values(curr.artists).reduce((acc, count) => acc + count, 0);
      Object.values(allArtists).forEach((art) => {
        obj[art.id] = (curr.artists[art.id] ?? 0) / total;
      });
      return obj;
    }, []);
    return buildXYDataObjSpread(d, Object.keys(allArtists), interval.start, interval.end, false);
  }, [allArtists, interval, resultsWithCount]);

  const tooltipLabelFormatter = useRawTooltipLabelFormatter(formatXAxisDateTooltip, false);

  const tooltipValueFormatter = useCallback(
    (value: number, label: string) => {
      if (value === 0) {
        return [<span />];
      }
      return [`${allArtists[label].name}: ${Math.floor(value * 1000) / 10}%`];
    },
    [allArtists],
  );

  const tooltipSorter = useCallback((a: any) => {
    return -a.payload[a.dataKey];
  }, []);

  const formatX = useFormatXAxis(data);

  if (!results) {
    return <LoadingImplementedChart title="Artist listening distribution" className={className} />;
  }

  return (
    <ChartCard title="Artist listening distribution" className={className}>
      <ResponsiveContainer width="100%" height="100%">
        <AreaChart data={data}>
          <XAxis dataKey="x" tickFormatter={formatX} style={{ fontWeight: 'bold' }} />
          <YAxis domain={[0, 1]} tickFormatter={formatYAxis} />
          <Tooltip
            formatter={tooltipValueFormatter}
            labelFormatter={tooltipLabelFormatter}
            wrapperStyle={{ zIndex: 1000 }}
            contentStyle={{ background: 'var(--background)' }}
            itemSorter={tooltipSorter}
          />
          {Object.values(allArtists).map((art, idx) => (
            <Area
              type="monotone"
              dataKey={art.id}
              key={art.id}
              stackId={-1}
              stroke={getColor(idx)}
              fill={getColor(idx)}
            />
          ))}
        </AreaChart>
      </ResponsiveContainer>
    </ChartCard>
  );
}
Example #16
Source File: LinearGraphWidget.tsx    From console with GNU Affero General Public License v3.0 4 votes vote down vote up
LinearGraphWidget = ({
  classes,
  title,

  timeStart,
  timeEnd,
  propLoading,
  panelItem,
  apiPrefix,
  hideYAxis = false,
  areaWidget = false,
  yAxisFormatter = (item: string) => item,
  xAxisFormatter = (item: string) => item,
  zoomActivated = false,
}: ILinearGraphWidget) => {
  const dispatch = useDispatch();
  const [loading, setLoading] = useState<boolean>(true);
  const [data, setData] = useState<object[]>([]);
  const [dataMax, setDataMax] = useState<number>(0);
  const [result, setResult] = useState<IDashboardPanel | null>(null);

  useEffect(() => {
    if (propLoading) {
      setLoading(true);
    }
  }, [propLoading]);

  useEffect(() => {
    if (loading) {
      let stepCalc = 0;
      if (timeStart !== null && timeEnd !== null) {
        const secondsInPeriod = timeEnd.unix() - timeStart.unix();
        const periods = Math.floor(secondsInPeriod / 60);

        stepCalc = periods < 1 ? 15 : periods;
      }

      api
        .invoke(
          "GET",
          `/api/v1/${apiPrefix}/info/widgets/${
            panelItem.id
          }/?step=${stepCalc}&${
            timeStart !== null ? `&start=${timeStart.unix()}` : ""
          }${timeStart !== null && timeEnd !== null ? "&" : ""}${
            timeEnd !== null ? `end=${timeEnd.unix()}` : ""
          }`
        )
        .then((res: any) => {
          const widgetsWithValue = widgetDetailsToPanel(res, panelItem);
          setData(widgetsWithValue.data);
          setResult(widgetsWithValue);
          setLoading(false);
          let maxVal = 0;
          for (const dp of widgetsWithValue.data) {
            for (const key in dp) {
              if (key === "name") {
                continue;
              }
              let val = parseInt(dp[key]);

              if (isNaN(val)) {
                val = 0;
              }

              if (maxVal < val) {
                maxVal = val;
              }
            }
          }
          setDataMax(maxVal);
        })
        .catch((err: ErrorResponseHandler) => {
          dispatch(setErrorSnackMessage(err));
          setLoading(false);
        });
    }
  }, [loading, panelItem, timeEnd, timeStart, dispatch, apiPrefix]);

  let intervalCount = Math.floor(data.length / 5);

  const linearConfiguration = result
    ? (result?.widgetConfiguration as ILinearGraphConfiguration[])
    : [];

  const CustomizedDot = (prop: any) => {
    const { cx, cy, index } = prop;

    if (index % 3 !== 0) {
      return null;
    }
    return <circle cx={cx} cy={cy} r={3} strokeWidth={0} fill="#07264A" />;
  };

  const theme = useTheme();
  const biggerThanMd = useMediaQuery(theme.breakpoints.up("md"));

  return (
    <Box className={zoomActivated ? "" : classes.singleValueContainer}>
      {!zoomActivated && (
        <div className={classes.titleContainer}>
          {title} <ExpandGraphLink panelItem={panelItem} />
        </div>
      )}
      <Box
        sx={
          zoomActivated
            ? { flexDirection: "column" }
            : {
                height: "100%",
                display: "grid",
                gridTemplateColumns: {
                  md: "1fr 1fr",
                  sm: "1fr",
                },
              }
        }
        style={areaWidget ? { gridTemplateColumns: "1fr" } : {}}
      >
        {loading && <Loader className={classes.loadingAlign} />}
        {!loading && (
          <React.Fragment>
            <div
              className={
                zoomActivated ? classes.zoomChartCont : classes.chartCont
              }
            >
              <ResponsiveContainer width="99%">
                <AreaChart
                  data={data}
                  margin={{
                    top: 5,
                    right: 20,
                    left: hideYAxis ? 20 : 5,
                    bottom: 0,
                  }}
                >
                  {areaWidget && (
                    <defs>
                      <linearGradient id="colorUv" x1="0" y1="0" x2="0" y2="1">
                        <stop offset="0%" stopColor="#2781B0" stopOpacity={1} />
                        <stop
                          offset="100%"
                          stopColor="#ffffff"
                          stopOpacity={0}
                        />

                        <stop
                          offset="95%"
                          stopColor="#ffffff"
                          stopOpacity={0.8}
                        />
                      </linearGradient>
                    </defs>
                  )}
                  <CartesianGrid
                    strokeDasharray={areaWidget ? "2 2" : "5 5"}
                    strokeWidth={1}
                    strokeOpacity={1}
                    stroke={"#eee0e0"}
                    vertical={!areaWidget}
                  />
                  <XAxis
                    dataKey="name"
                    tickFormatter={(value: any) => xAxisFormatter(value)}
                    interval={intervalCount}
                    tick={{
                      fontSize: "68%",
                      fontWeight: "normal",
                      color: "#404143",
                    }}
                    tickCount={10}
                    stroke={"#082045"}
                  />
                  <YAxis
                    type={"number"}
                    domain={[0, dataMax * 1.1]}
                    hide={hideYAxis}
                    tickFormatter={(value: any) => yAxisFormatter(value)}
                    tick={{
                      fontSize: "68%",
                      fontWeight: "normal",
                      color: "#404143",
                    }}
                    stroke={"#082045"}
                  />
                  {linearConfiguration.map((section, index) => {
                    return (
                      <Area
                        key={`area-${section.dataKey}-${index.toString()}`}
                        type="monotone"
                        dataKey={section.dataKey}
                        isAnimationActive={false}
                        stroke={!areaWidget ? section.lineColor : "#D7E5F8"}
                        fill={areaWidget ? "url(#colorUv)" : section.fillColor}
                        fillOpacity={areaWidget ? 0.65 : 0}
                        strokeWidth={!areaWidget ? 3 : 0}
                        strokeLinecap={"round"}
                        dot={areaWidget ? <CustomizedDot /> : false}
                      />
                    );
                  })}
                  <Tooltip
                    content={
                      <LineChartTooltip
                        linearConfiguration={linearConfiguration}
                        yAxisFormatter={yAxisFormatter}
                      />
                    }
                    wrapperStyle={{
                      zIndex: 5000,
                    }}
                  />
                </AreaChart>
              </ResponsiveContainer>
            </div>
            {!areaWidget && (
              <Fragment>
                {zoomActivated && (
                  <Fragment>
                    <strong>Series</strong>
                    <br />
                    <br />
                  </Fragment>
                )}
                {biggerThanMd && (
                  <div className={classes.legendChart}>
                    {linearConfiguration.map((section, index) => {
                      return (
                        <div
                          className={classes.singleLegendContainer}
                          key={`legend-${section.keyLabel}-${index.toString()}`}
                        >
                          <div
                            className={classes.colorContainer}
                            style={{ backgroundColor: section.lineColor }}
                          />
                          <div className={classes.legendLabel}>
                            {section.keyLabel}
                          </div>
                        </div>
                      );
                    })}
                  </div>
                )}
              </Fragment>
            )}
          </React.Fragment>
        )}
      </Box>
    </Box>
  );
}
Example #17
Source File: LiveMetricsItem.tsx    From kubenav with MIT License 4 votes vote down vote up
LiveMetricsItem: React.FunctionComponent<ILiveMetricsItemProps> = ({
  show,
  hide,
  item,
}: ILiveMetricsItemProps) => {
  const context = useContext<IContext>(AppContext);
  const [metrics, setMetrics] = useState<ILiveMetric[]>([]);

  const fetchMetrics = async () => {
    try {
      if (show) {
        const data: IPodMetrics = await kubernetesRequest(
          'GET',
          `/apis/metrics.k8s.io/v1beta1/namespaces/${
            item.metadata && item.metadata.namespace ? item.metadata.namespace : ''
          }/pods/${item.metadata && item.metadata.name ? item.metadata.name : ''}`,
          '',
          context.settings,
          await context.kubernetesAuthWrapper(''),
        );

        const containerMetrics: ILiveMetric[] = [];

        if (data.containers) {
          for (const container of data.containers) {
            containerMetrics.push({
              timestamp: 0,
              cpu: parseInt(formatResourceValue('cpu', container?.usage?.cpu || '0')),
              memory: parseInt(formatResourceValue('memory', container?.usage?.memory || '0')),
            });
          }
        }

        setMetrics((prevMetrics) => {
          if (prevMetrics.length > 14) {
            return [
              ...prevMetrics.slice(-14),
              {
                timestamp: Math.floor(new Date().getTime() / 1000),
                cpu: containerMetrics.map((m) => m.cpu).reduce(reducer),
                memory: containerMetrics.map((m) => m.memory).reduce(reducer),
              },
            ];
          } else {
            return [
              ...prevMetrics,
              {
                timestamp: Math.floor(new Date().getTime() / 1000),
                cpu: containerMetrics.map((m) => m.cpu).reduce(reducer),
                memory: containerMetrics.map((m) => m.memory).reduce(reducer),
              },
            ];
          }
        });
      }
    } catch (err) {
      throw err;
    }
  };

  const formatTime = (time: number): string => {
    const d = new Date(time * 1000);
    return `${('0' + d.getHours()).slice(-2)}:${('0' + d.getMinutes()).slice(-2)}:${('0' + d.getSeconds()).slice(-2)}`;
  };

  useEffect(() => {
    const timer = setTimeout(() => {
      fetchMetrics();
    }, 3000);

    return () => clearTimeout(timer);
  });

  return (
    <React.Fragment>
      <IonModal isOpen={show} onDidDismiss={hide}>
        <IonHeader>
          <IonToolbar>
            <IonButtons slot="start">
              <IonButton onClick={hide}>
                <IonIcon slot="icon-only" icon={close} />
              </IonButton>
            </IonButtons>
            <IonTitle>{item.metadata ? item.metadata.name : ''}</IonTitle>
          </IonToolbar>
        </IonHeader>
        <IonContent>
          <IonCard>
            <IonCardHeader>
              <IonCardTitle>CPU Usage</IonCardTitle>
            </IonCardHeader>
            <IonCardContent>
              <div style={{ height: '300px', width: '100%' }}>
                {metrics.length > 0 && (
                  <ResponsiveContainer>
                    <AreaChart data={metrics}>
                      <XAxis
                        dataKey="timestamp"
                        scale="time"
                        type="number"
                        domain={['dataMin', 'dataMax']}
                        tickFormatter={formatTime}
                      />
                      <YAxis dataKey="cpu" unit="m" />
                      <Area
                        dataKey="cpu"
                        // NOTE: https://github.com/recharts/recharts/issues/2487
                        // eslint-disable-next-line @typescript-eslint/ban-ts-comment
                        // @ts-ignore
                        data={metrics}
                        name="CPU Usage"
                        stroke="#326ce5"
                        fill="#326ce5"
                        fillOpacity={0.2}
                        isAnimationActive={false}
                      />
                    </AreaChart>
                  </ResponsiveContainer>
                )}
              </div>
            </IonCardContent>
          </IonCard>
          <IonCard>
            <IonCardHeader>
              <IonCardTitle>Memory Usage</IonCardTitle>
            </IonCardHeader>
            <IonCardContent>
              <div style={{ height: '300px', width: '100%' }}>
                {metrics.length > 0 && (
                  <ResponsiveContainer>
                    <AreaChart data={metrics}>
                      <XAxis
                        dataKey="timestamp"
                        scale="time"
                        type="number"
                        domain={['dataMin', 'dataMax']}
                        tickFormatter={formatTime}
                      />
                      <YAxis dataKey="memory" unit="Mi" />
                      <Area
                        dataKey="memory"
                        // NOTE: https://github.com/recharts/recharts/issues/2487
                        // eslint-disable-next-line @typescript-eslint/ban-ts-comment
                        // @ts-ignore
                        data={metrics}
                        name="Memory Usage"
                        stroke="#326ce5"
                        fill="#326ce5"
                        fillOpacity={0.2}
                        isAnimationActive={false}
                      />
                    </AreaChart>
                  </ResponsiveContainer>
                )}
              </div>
            </IonCardContent>
          </IonCard>
        </IonContent>
      </IonModal>
    </React.Fragment>
  );
}
Example #18
Source File: ChartDetailsArea.tsx    From kubenav with MIT License 4 votes vote down vote up
ChartDetailsArea: React.FunctionComponent<IChartDetailsAreaProps> = ({
  unit,
  timeDiff,
  results,
}: IChartDetailsAreaProps) => {
  const context = useContext<IContext>(AppContext);
  const [selected, setSelected] = useState<string>('');

  // formatTime is use to formate the shown values for the x axis. If the user selected a time span lower then 24h we
  // are showing the "hh:mm" for timespans larger then 24h we are showing "MM/DD hh:mm".
  const formatTime = (time: number): string => {
    const d = new Date(time * 1000);

    if (timeDiff >= 86400) {
      return `${('0' + (d.getMonth() + 1)).slice(-2)}/${('0' + d.getDate()).slice(-2)} ${('0' + d.getHours()).slice(
        -2,
      )}:${('0' + d.getMinutes()).slice(-2)}`;
    } else {
      return `${('0' + d.getHours()).slice(-2)}:${('0' + d.getMinutes()).slice(-2)}`;
    }
  };

  // The series variables contains the transformed Prometheus results. This is necessary, because the returned formate
  // from Prometheus can not directly used with Recharts.
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  const series: any = [];

  for (let i = 0; i < results.length; i++) {
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    const data: any = [];
    for (let j = 0; j < results[i].values.length; j++) {
      data.push({
        time: results[i].values[j][0],
        value: parseFloat(results[i].values[j][1]),
      });
    }
    series.push({ name: results[i].label, data: data });
  }

  return (
    <IonRow style={{ height: '300px', width: '100%' }}>
      <IonCol style={{ padding: '0px' }}>
        <ResponsiveContainer>
          <AreaChart data={series[0].data}>
            <XAxis
              dataKey="time"
              scale="time"
              type="number"
              domain={['dataMin', 'dataMax']}
              tickFormatter={formatTime}
            />
            <YAxis dataKey="value" unit={unit} />
            <Legend
              height={40}
              wrapperStyle={{ overflowY: 'auto' }}
              onClick={(e) => (selected === e.payload.name ? setSelected('') : setSelected(e.payload.name))}
            />
            {!isPlatform('hybrid') ? (
              <Tooltip
                cursor={{ stroke: '#949494', strokeWidth: 2 }}
                contentStyle={
                  isDarkMode(context.settings.theme)
                    ? isPlatform('ios')
                      ? { backgroundColor: '1c1c1c', borderColor: '#949494' }
                      : { backgroundColor: '#1A1B1E', borderColor: '#949494' }
                    : { backgroundColor: '#ffffff', borderColor: '#949494' }
                }
                formatter={(value) => {
                  return `${value.toFixed(5)} ${unit ? unit : ''}`;
                }}
                labelFormatter={formatTime}
              />
            ) : null}
            {selected === ''
              ? series.map((serie, index) => (
                  <Area
                    key={index}
                    dataKey="value"
                    // NOTE: https://github.com/recharts/recharts/issues/2487
                    // eslint-disable-next-line @typescript-eslint/ban-ts-comment
                    // @ts-ignore
                    data={serie.data}
                    name={serie.name}
                    stroke={getColor(index, isDarkMode(context.settings.theme))}
                    fill={getColor(index, isDarkMode(context.settings.theme))}
                    fillOpacity={0.2}
                  />
                ))
              : series
                  .filter((serie) => serie.name === selected)
                  .map((serie, index) => (
                    <Area
                      key={index}
                      dataKey="value"
                      // NOTE: https://github.com/recharts/recharts/issues/2487
                      // eslint-disable-next-line @typescript-eslint/ban-ts-comment
                      // @ts-ignore
                      data={serie.data}
                      name={serie.name}
                      stroke={getColor(
                        series.findIndex((s) => s.name === selected),
                        isDarkMode(context.settings.theme),
                      )}
                      fill={getColor(
                        series.findIndex((s) => s.name === selected),
                        isDarkMode(context.settings.theme),
                      )}
                      fillOpacity={0.2}
                    />
                  ))}
          </AreaChart>
        </ResponsiveContainer>
      </IonCol>
    </IonRow>
  );
}
Example #19
Source File: CostOverviewBreakdownChart.tsx    From backstage with Apache License 2.0 4 votes vote down vote up
CostOverviewBreakdownChart = ({
  costBreakdown,
}: CostOverviewBreakdownChartProps) => {
  const theme = useTheme<CostInsightsTheme>();
  const classes = useStyles(theme);
  const lastCompleteBillingDate = useLastCompleteBillingDate();
  const { duration } = useFilters(mapFiltersToProps);
  const [isExpanded, setExpanded] = useState(false);

  if (!costBreakdown) {
    return null;
  }

  const flattenedAggregation = costBreakdown
    .map(cost => cost.aggregation)
    .flat();

  const totalCost = aggregationSum(flattenedAggregation);

  const previousPeriodTotal = getPreviousPeriodTotalCost(
    flattenedAggregation,
    duration,
    lastCompleteBillingDate,
  );
  const currentPeriodTotal = totalCost - previousPeriodTotal;
  const canExpand = costBreakdown.length >= 8;
  const otherCategoryIds: string[] = [];

  const breakdownsByDate = costBreakdown.reduce(
    (breakdownByDate, breakdown) => {
      const breakdownTotal = aggregationSum(breakdown.aggregation);
      // Group breakdown items with less than 10% of the total cost into "Other" category if needed
      const isOtherCategory =
        canExpand && breakdownTotal < totalCost * LOW_COST_THRESHOLD;

      const updatedBreakdownByDate = { ...breakdownByDate };
      if (isOtherCategory) {
        otherCategoryIds.push(breakdown.id);
      }
      breakdown.aggregation.forEach(curAggregation => {
        const costsForDate = updatedBreakdownByDate[curAggregation.date] || {};

        updatedBreakdownByDate[curAggregation.date] = {
          ...costsForDate,
          [breakdown.id]:
            (costsForDate[breakdown.id] || 0) + curAggregation.amount,
        };
      });

      return updatedBreakdownByDate;
    },
    {} as Record<string, Record<string, number>>,
  );

  const chartData: Record<string, number>[] = Object.keys(breakdownsByDate).map(
    date => {
      const costsForDate = Object.keys(breakdownsByDate[date]).reduce(
        (dateCosts, breakdown) => {
          // Group costs for items that belong to 'Other' in the chart.
          const cost = breakdownsByDate[date][breakdown];
          const breakdownCost =
            !isExpanded && otherCategoryIds.includes(breakdown)
              ? { Other: (dateCosts.Other || 0) + cost }
              : { [breakdown]: cost };
          return { ...dateCosts, ...breakdownCost };
        },
        {} as Record<string, number>,
      );
      return {
        ...costsForDate,
        date: Date.parse(date),
      };
    },
  );

  const sortedBreakdowns = costBreakdown.sort(
    (a, b) => aggregationSum(a.aggregation) - aggregationSum(b.aggregation),
  );

  const renderAreas = () => {
    const separatedBreakdowns = sortedBreakdowns
      // Check that the breakdown is a separate group and hasn't been added to 'Other'
      .filter(
        breakdown =>
          breakdown.id !== 'Other' && !otherCategoryIds.includes(breakdown.id),
      )
      .map(breakdown => breakdown.id);
    // Keep 'Other' category at the bottom of the stack
    const breakdownsToDisplay = isExpanded
      ? sortedBreakdowns.map(breakdown => breakdown.id)
      : ['Other', ...separatedBreakdowns];

    return breakdownsToDisplay.map((breakdown, i) => {
      // Logic to handle case where there are more items than data viz colors.
      const color =
        theme.palette.dataViz[
          (breakdownsToDisplay.length - 1 - i) %
            (theme.palette.dataViz.length - 1)
        ];
      return (
        <Area
          key={breakdown}
          dataKey={breakdown}
          isAnimationActive={false}
          stackId="1"
          stroke={color}
          fill={color}
          onClick={() => setExpanded(true)}
          style={{
            cursor: breakdown === 'Other' && !isExpanded ? 'pointer' : null,
          }}
        />
      );
    });
  };

  const tooltipRenderer: ContentRenderer<TooltipProps> = ({
    label,
    payload = [],
  }) => {
    if (isInvalid({ label, payload })) return null;

    const date =
      typeof label === 'number'
        ? DateTime.fromMillis(label)
        : DateTime.fromISO(label!);
    const dateTitle = date.toUTC().toFormat(DEFAULT_DATE_FORMAT);
    const items = payload.map(p => ({
      label: p.dataKey as string,
      value: formatGraphValue(p.value as number),
      fill: p.fill!,
    }));
    const expandText = (
      <Box>
        <Divider
          style={{
            backgroundColor: emphasize(theme.palette.divider, 1),
            margin: '10px 0',
          }}
        />
        <Box display="flex" justifyContent="space-between" alignItems="center">
          <FullScreenIcon />
          <Typography>Click to expand</Typography>
        </Box>
      </Box>
    );
    return (
      <Tooltip title={dateTitle}>
        {items.reverse().map((item, index) => (
          <TooltipItem key={`${item.label}-${index}`} item={item} />
        ))}
        {canExpand && !isExpanded ? expandText : null}
      </Tooltip>
    );
  };

  const options: Partial<BarChartLegendOptions> = {
    previousName: formatPeriod(duration, lastCompleteBillingDate, false),
    currentName: formatPeriod(duration, lastCompleteBillingDate, true),
    hideMarker: true,
  };

  return (
    <Box display="flex" flexDirection="column">
      <Box display="flex" flexDirection="row">
        <BarChartLegend
          costStart={previousPeriodTotal}
          costEnd={currentPeriodTotal}
          options={options}
        />
      </Box>
      <ResponsiveContainer
        width={classes.container.width}
        height={classes.container.height}
      >
        <AreaChart
          data={chartData}
          margin={{
            top: 16,
            right: 30,
            bottom: 40,
          }}
        >
          <CartesianGrid stroke={classes.cartesianGrid.stroke} />
          <XAxis
            dataKey="date"
            domain={['dataMin', 'dataMax']}
            tickFormatter={overviewGraphTickFormatter}
            tickCount={6}
            type="number"
            stroke={classes.axis.fill}
          />
          <YAxis
            domain={[() => 0, 'dataMax']}
            tick={{ fill: classes.axis.fill }}
            tickFormatter={formatGraphValue}
            width={classes.yAxis.width}
          />
          {renderAreas()}
          <RechartsTooltip content={tooltipRenderer} animationDuration={100} />
        </AreaChart>
      </ResponsiveContainer>
    </Box>
  );
}