recharts#LegendProps TypeScript Examples

The following examples show how to use recharts#LegendProps. 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: stage-chart.tsx    From backstage with Apache License 2.0 4 votes vote down vote up
export function StageChart(props: StageChartProps) {
  const { stage, ...chartOptions } = props;
  const {
    chartTypes,
    defaultCollapsed = 0,
    defaultHidden = 0,
    zeroYAxis = false,
  } = chartOptions;

  const { zoomFilterValues } = useZoom();
  const { zoomProps, getZoomArea } = useZoomArea();

  const ticks = useMemo(
    () => pickElements(stage.values, 8).map(val => val.__epoch),
    [stage.values],
  );
  const domainY = useMemo(
    () => [zeroYAxis ? 0 : 'auto', 'auto'] as YAxisProps['domain'],
    [zeroYAxis],
  );
  const statuses = useMemo(
    () => statusTypes.filter(status => stage.statusSet.has(status)),
    [stage.statusSet],
  );
  const legendPayload = useMemo(
    (): LegendProps['payload'] =>
      statuses.map(status => ({
        value: capitalize(status),
        type: 'line',
        id: status,
        color: statusColorMap[status],
      })),
    [statuses],
  );

  const subStages = useMemo(
    () =>
      new Map<string, ChartableStage>(
        [...stage.stages.entries()].filter(
          ([_name, subStage]) => subStage.combinedAnalysis.max > defaultHidden,
        ),
      ),
    [stage.stages, defaultHidden],
  );

  const zoomFilteredValues = useMemo(
    () => zoomFilterValues(stage.values),
    [stage.values, zoomFilterValues],
  );

  return stage.combinedAnalysis.max < defaultHidden ? null : (
    <Accordion
      defaultExpanded={stage.combinedAnalysis.max > defaultCollapsed}
      TransitionProps={transitionProps}
    >
      <AccordionSummary expandIcon={<ExpandMoreIcon />}>
        <Typography>
          {stage.name} (med {formatDuration(stage.combinedAnalysis.med)}, avg{' '}
          {formatDuration(stage.combinedAnalysis.avg)})
        </Typography>
      </AccordionSummary>
      <AccordionDetails>
        {stage.values.length === 0 ? (
          <Alert severity="info">No data</Alert>
        ) : (
          <Grid container direction="column">
            <Grid item style={noUserSelect}>
              <ResponsiveContainer width="100%" height={140}>
                <ComposedChart data={zoomFilteredValues} {...zoomProps}>
                  <defs>
                    <linearGradient id="colorDur" x1="0" y1="0" x2="0" y2="1">
                      {fireColors.map(([percent, color]) => (
                        <stop
                          key={percent}
                          offset={percent}
                          stopColor={color}
                          stopOpacity={0.8}
                        />
                      ))}
                    </linearGradient>
                  </defs>
                  {statuses.length > 1 && <Legend payload={legendPayload} />}
                  <CartesianGrid strokeDasharray="3 3" />
                  <XAxis
                    dataKey="__epoch"
                    type="category"
                    ticks={ticks}
                    tickFormatter={tickFormatterX}
                  />
                  <YAxis
                    yAxisId={1}
                    tickFormatter={tickFormatterY}
                    type="number"
                    tickCount={5}
                    name="Duration"
                    domain={domainY}
                  />
                  <YAxis
                    yAxisId={2}
                    orientation="right"
                    type="number"
                    tickCount={5}
                    name="Count"
                  />
                  <Tooltip
                    formatter={tooltipValueFormatter}
                    labelFormatter={labelFormatter}
                  />
                  {statuses.reverse().map(status => (
                    <Fragment key={status}>
                      {!chartTypes[status].includes('duration') ? null : (
                        <>
                          <Area
                            isAnimationActive={false}
                            yAxisId={1}
                            type="monotone"
                            dataKey={status}
                            stackId={status}
                            stroke={
                              statuses.length > 1
                                ? statusColorMap[status]
                                : colorStroke
                            }
                            fillOpacity={statuses.length > 1 ? 0.5 : 1}
                            fill={
                              statuses.length > 1
                                ? statusColorMap[status]
                                : 'url(#colorDur)'
                            }
                            connectNulls
                          />
                          <Line
                            isAnimationActive={false}
                            yAxisId={1}
                            type="monotone"
                            dataKey={`${status} avg`}
                            stroke={
                              statuses.length > 1
                                ? statusColorMap[status]
                                : colorStrokeAvg
                            }
                            opacity={0.8}
                            strokeWidth={2}
                            dot={false}
                            connectNulls
                          />
                        </>
                      )}
                      {!chartTypes[status].includes('count') ? null : (
                        <Bar
                          isAnimationActive={false}
                          yAxisId={2}
                          type="monotone"
                          dataKey={`${status} count`}
                          stackId="1"
                          stroke={statusColorMap[status] ?? ''}
                          fillOpacity={0.5}
                          fill={statusColorMap[status] ?? ''}
                        />
                      )}
                    </Fragment>
                  ))}
                  {getZoomArea({ yAxisId: 1 })}
                </ComposedChart>
              </ResponsiveContainer>
            </Grid>
            {subStages.size === 0 ? null : (
              <Grid item>
                <Accordion
                  defaultExpanded={false}
                  TransitionProps={transitionProps}
                >
                  <AccordionSummary expandIcon={<ExpandMoreIcon />}>
                    <Typography>Sub stages ({subStages.size})</Typography>
                  </AccordionSummary>
                  <AccordionDetails>
                    <div style={fullWidth}>
                      {[...subStages.values()].map(subStage => (
                        <StageChart
                          key={subStage.name}
                          {...chartOptions}
                          stage={subStage}
                        />
                      ))}
                    </div>
                  </AccordionDetails>
                </Accordion>
              </Grid>
            )}
          </Grid>
        )}
      </AccordionDetails>
    </Accordion>
  );
}
Example #2
Source File: status-chart.tsx    From backstage with Apache License 2.0 4 votes vote down vote up
export function StatusChart(props: StatusChartProps) {
  const { analysis } = props;

  const { zoomFilterValues } = useZoom();
  const { zoomProps, getZoomArea } = useZoomArea();

  const values = useMemo(() => {
    return analysis.daily.values.map(value => {
      const totTriggers = analysis.daily.triggerReasons.reduce(
        (prev, cur) => prev + (value[cur as TriggerReason] ?? 0),
        0,
      );

      if (!totTriggers) {
        return value;
      }

      return {
        ...value,
        ...Object.fromEntries(
          analysis.daily.triggerReasons.map(reason => [
            reason,
            (value[reason as TriggerReason] ?? 0) / totTriggers,
          ]),
        ),
      };
    });
  }, [analysis.daily]);

  const triggerReasonLegendPayload = useMemo(
    (): NonNullable<LegendProps['payload']> =>
      analysis.daily.triggerReasons.map(reason => ({
        value: humanTriggerReason(reason),
        type: 'line',
        id: reason,
        color: triggerColorMap[reason as TriggerReason] ?? '',
      })),
    [analysis.daily.triggerReasons],
  );

  const statusesLegendPayload = useMemo(
    (): NonNullable<LegendProps['payload']> =>
      analysis.daily.statuses.map(status => ({
        value: capitalize(status),
        type: 'line',
        id: status,
        color: statusColorMap[status as FilterStatusType] ?? '',
      })),
    [analysis.daily.statuses],
  );

  const legendPayload = useMemo(
    (): NonNullable<LegendProps['payload']> => [
      ...triggerReasonLegendPayload,
      ...statusesLegendPayload,
    ],
    [statusesLegendPayload, triggerReasonLegendPayload],
  );

  const tooltipFormatter = useMemo(() => {
    const reasonSet = new Set(analysis.daily.triggerReasons);

    return (percentOrCount: number, name: string) => {
      const label = reasonSet.has(name)
        ? humanTriggerReason(name)
        : capitalize(name);
      const valueText = reasonSet.has(name)
        ? `${(percentOrCount * 100).toFixed(0)}%`
        : percentOrCount;

      return [
        <span>
          {label}: {valueText}
        </span>,
        null,
      ];
    };
  }, [analysis.daily.triggerReasons]);

  const zoomFilteredValues = useMemo(
    () => zoomFilterValues(values),
    [values, zoomFilterValues],
  );

  const barSize = getBarSize(analysis.daily.values.length);

  return (
    <Accordion defaultExpanded={analysis.daily.statuses.length > 1}>
      <AccordionSummary expandIcon={<ExpandMoreIcon />}>
        <Typography>
          Build count per status over build trigger reason
        </Typography>
      </AccordionSummary>
      <AccordionDetails>
        {values.length === 0 ? (
          <Alert severity="info">No data</Alert>
        ) : (
          <ResponsiveContainer width="100%" height={140}>
            <ComposedChart data={zoomFilteredValues} {...zoomProps}>
              <Legend payload={legendPayload} />
              <CartesianGrid strokeDasharray="3 3" />
              <XAxis
                dataKey="__epoch"
                type="category"
                tickFormatter={tickFormatterX}
              />
              <YAxis yAxisId={1} type="number" tickCount={5} name="Count" />
              <YAxis yAxisId={2} type="number" name="Triggers" hide />
              <Tooltip
                labelFormatter={labelFormatterWithoutTime}
                formatter={tooltipFormatter}
              />
              {triggerReasonLegendPayload.map(reason => (
                <Fragment key={reason.id}>
                  <Area
                    isAnimationActive={false}
                    type="monotone"
                    dataKey={reason.id!}
                    stackId="triggers"
                    yAxisId={2}
                    stroke={triggerColorMap[reason.id as TriggerReason] ?? ''}
                    fillOpacity={0.5}
                    fill={triggerColorMap[reason.id as TriggerReason] ?? ''}
                  />
                </Fragment>
              ))}
              {[...analysis.daily.statuses].reverse().map(status => (
                <Fragment key={status}>
                  <Bar
                    isAnimationActive={false}
                    type="monotone"
                    barSize={barSize}
                    dataKey={status}
                    stackId="statuses"
                    yAxisId={1}
                    stroke={statusColorMap[status as FilterStatusType] ?? ''}
                    fillOpacity={0.8}
                    fill={statusColorMap[status as FilterStatusType] ?? ''}
                  />
                </Fragment>
              ))}
              {getZoomArea({ yAxisId: 1 })}
            </ComposedChart>
          </ResponsiveContainer>
        )}
      </AccordionDetails>
    </Accordion>
  );
}