recharts#Legend TypeScript Examples

The following examples show how to use recharts#Legend. 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: PeriodByResponderGraph.tsx    From backstage-plugin-opsgenie with MIT License 6 votes vote down vote up
PeriodByResponderGraph = ({data}: {data: IncidentsByResponders}) => {
    return (
        <ResponsiveContainer>
            <ComposedChart data={data.dataPoints}>
                <CartesianGrid strokeDasharray="3 3" />
                <XAxis dataKey="period" />
                <YAxis />
                {data.responders.map(responder => (
                    <Bar dataKey={responder} fill={colorForString(responder)} stackId="a" barSize={30}  key={responder} />
                ))}
                <Line type="monotone" dataKey="total" name="Total" stroke="#ff7300" />
                <Tooltip content={<FilterZeroTooltip />} />
                <Legend />
            </ComposedChart>
        </ResponsiveContainer>
    );
}
Example #2
Source File: Debug.tsx    From watchparty with MIT License 6 votes vote down vote up
Debug = () => {
  const [data, setData] = useState([]);
  // eslint-disable-next-line
  useEffect(
    (async () => {
      const response = await fetch(timeSeriesUrl);
      const json = await response.json();
      json.reverse();
      setData(json);
    }) as any,
    [setData]
  );
  const keys = Object.keys(data.slice(-1)[0] ?? {});
  return (
    <>
      {keys.map((key) => (
        <LineChart
          width={1400}
          height={400}
          data={data}
          margin={{
            top: 5,
            left: 20,
            bottom: 5,
          }}
        >
          <CartesianGrid />
          <XAxis dataKey="time" />
          <YAxis />
          <Tooltip />
          <Legend />
          <Line type="monotone" dataKey={key} stroke="#8884d8" />
        </LineChart>
      ))}
    </>
  );
}
Example #3
Source File: QueueSizeChart.tsx    From asynqmon with MIT License 6 votes vote down vote up
function QueueSizeChart(props: Props) {
  const theme = useTheme();
  const handleClick = (params: { activeLabel?: string } | null) => {
    const allQueues = props.data.map((b) => b.queue);
    if (
      params &&
      params.activeLabel &&
      allQueues.includes(params.activeLabel)
    ) {
      history.push(queueDetailsPath(params.activeLabel));
    }
  };
  const history = useHistory();
  return (
    <ResponsiveContainer>
      <BarChart
        data={props.data}
        maxBarSize={120}
        onClick={handleClick}
        style={{ cursor: "pointer" }}
      >
        <CartesianGrid strokeDasharray="3 3" />
        <XAxis dataKey="queue" stroke={theme.palette.text.secondary} />
        <YAxis stroke={theme.palette.text.secondary} />
        <Tooltip />
        <Legend />
        <Bar dataKey="active" stackId="a" fill="#1967d2" />
        <Bar dataKey="pending" stackId="a" fill="#669df6" />
        <Bar dataKey="aggregating" stackId="a" fill="#e69138" />
        <Bar dataKey="scheduled" stackId="a" fill="#fdd663" />
        <Bar dataKey="retry" stackId="a" fill="#f666a9" />
        <Bar dataKey="archived" stackId="a" fill="#ac4776" />
        <Bar dataKey="completed" stackId="a" fill="#4bb543" />
      </BarChart>
    </ResponsiveContainer>
  );
}
Example #4
Source File: ProcessedTasksChart.tsx    From asynqmon with MIT License 6 votes vote down vote up
function ProcessedTasksChart(props: Props) {
  const theme = useTheme<Theme>();
  return (
    <ResponsiveContainer>
      <BarChart data={props.data} maxBarSize={120}>
        <CartesianGrid strokeDasharray="3 3" />
        <XAxis dataKey="queue" stroke={theme.palette.text.secondary} />
        <YAxis stroke={theme.palette.text.secondary} />
        <Tooltip />
        <Legend />
        <Bar
          dataKey="succeeded"
          stackId="a"
          fill={theme.palette.success.light}
        />
        <Bar dataKey="failed" stackId="a" fill={theme.palette.error.light} />
      </BarChart>
    </ResponsiveContainer>
  );
}
Example #5
Source File: DailyStatsChart.tsx    From asynqmon with MIT License 6 votes vote down vote up
export default function DailyStatsChart(props: Props) {
  const data = makeChartData(props.data, props.numDays);
  const theme = useTheme<Theme>();
  return (
    <ResponsiveContainer>
      <LineChart data={data}>
        <CartesianGrid strokeDasharray="3 3" />
        <XAxis
          dataKey="date"
          minTickGap={10}
          stroke={theme.palette.text.secondary}
        />
        <YAxis stroke={theme.palette.text.secondary} />
        <Tooltip />
        <Legend />
        <Line
          type="monotone"
          dataKey="succeeded"
          stroke={theme.palette.success.main}
        />
        <Line
          type="monotone"
          dataKey="failed"
          stroke={theme.palette.error.main}
        />
      </LineChart>
    </ResponsiveContainer>
  );
}
Example #6
Source File: ChartCard.tsx    From genshin-optimizer with MIT License 6 votes vote down vote up
function Chart({ displayData, plotNode, valueNode, showMin }: {
  displayData: Point[],
  plotNode: NumNode,
  valueNode: NumNode,
  showMin: boolean
}) {
  const plotBaseUnit = KeyMap.unit(plotNode.info?.key)
  const valueUnit = KeyMap.unit(valueNode.info?.key)
  return <ResponsiveContainer width="100%" height={600}>
    <ComposedChart data={displayData}>
      <CartesianGrid strokeDasharray="3 3" />
      <XAxis dataKey="x" scale="linear" unit={plotBaseUnit} domain={["auto", "auto"]} tick={{ fill: 'white' }} type="number" tickFormatter={n => n > 10000 ? n.toFixed() : n.toFixed(1)} />
      <YAxis name="DMG" domain={["auto", "auto"]} unit={valueUnit} allowDecimals={false} tick={{ fill: 'white' }} type="number" />
      <ZAxis dataKey="y" range={[3, 25]} />
      <Legend />
      <Scatter name="Optimization Target" dataKey="y" fill="#8884d8" line lineType="fitting" isAnimationActive={false} />
      {showMin && <Line name="Minimum Stat Requirement Threshold" dataKey="min" stroke="#ff7300" type="stepBefore" connectNulls strokeWidth={2} isAnimationActive={false} />}
    </ComposedChart>
  </ResponsiveContainer>
}
Example #7
Source File: ScatterChart.tsx    From opensaas with MIT License 6 votes vote down vote up
ScatterChart: React.FC<ScatterChartProps> = (props: ScatterChartProps) => {
  const { data, width, height, showGrid, strokeColor, fillColor, scatterName } = props;

  return (
    <ResponsiveContainer>
      <RechartsScatterChart width={width} height={height}>
        {showGrid ? <CartesianGrid strokeDasharray='3 3' /> : null}
        <XAxis type='number' dataKey='x' name={data?.xname} tickLine={false} />
        <YAxis type='number' dataKey='y' name={data?.yname} tickLine={false} />
        <Tooltip />
        <Legend
          verticalAlign='top'
          content={<CustomizedLegend strokeColor={strokeColor} fillColor={fillColor} scatterName={scatterName} />}
        />
        <Scatter
          name={scatterName}
          data={data.lineChartData}
          shape={<CustomizedDot strokeColor={strokeColor} fillColor={fillColor} r={6} cx={10} cy={10} />}
        />
      </RechartsScatterChart>
    </ResponsiveContainer>
  );
}
Example #8
Source File: PieChart.tsx    From opensaas with MIT License 6 votes vote down vote up
PieChart: React.FC<PieChartProps> = (props: PieChartProps) => {
  const { width, height, data = [], colors, pie } = props;

  return (
    <RechartsPieChart width={width} height={height}>
      <Tooltip />
      <Legend />
      <Pie
        data={data}
        cx={pie?.cx}
        cy={pie?.cy}
        innerRadius={pie?.innerRadius}
        outerRadius={pie?.outerRadius}
        fill='#8884d8'
        paddingAngle={pie?.paddingAngle}
        dataKey='value'>
        {data.map((_entry, index) => (
          <Cell key={`cell-${index}`} fill={colors[index % colors.length]} />
        ))}
      </Pie>
    </RechartsPieChart>
  );
}
Example #9
Source File: LineChart.tsx    From opensaas with MIT License 6 votes vote down vote up
LineChart: React.FC<LineChartProps> = (props) => {
  const { width, height, data, xAxis, line, showGrid, colors } = props;

  return (
    <ResponsiveContainer>
      <RechartsLineChart width={width} height={height}>
        {showGrid ? <CartesianGrid strokeDasharray='3 3' /> : null}
        <XAxis dataKey='category' type={xAxis.type} allowDuplicatedCategory={false} axisLine={false} tickLine={false} />
        <YAxis dataKey='value' axisLine={false} tickLine={false} />
        <Tooltip />
        <Legend verticalAlign='top' />
        {data.map(({ data, name }, index: number) => (
          <Line
            strokeWidth={line.strokeWidth}
            legendType='circle'
            type={line.type}
            stroke={colors[index % colors.length]}
            dataKey='value'
            data={data}
            name={name}
            key={name}
            activeDot={line.activeDot}
          />
        ))}
      </RechartsLineChart>
    </ResponsiveContainer>
  );
}
Example #10
Source File: BarChart.tsx    From opensaas with MIT License 6 votes vote down vote up
BarChart: React.FC<BarChartProps> = (props) => {
  const { width, height, data, barSize, barCategoryGap, showGrid, showLegend, colors } = props;
  return (
    <ResponsiveContainer>
      <RechartsBarChart
        width={width}
        height={height}
        data={data}
        barSize={barSize}
        barCategoryGap={barCategoryGap}
        margin={{
          top: 5,
          right: 30,
          left: 10,
          bottom: 5,
        }}>
        {showGrid ? <CartesianGrid strokeDasharray='3 3' /> : null}
        <XAxis dataKey='name' axisLine={false} tickLine={false} />
        <YAxis axisLine={false} tickLine={false} />
        <Tooltip cursor={false} />
        {showLegend ? <Legend /> : null}
        {Object.keys(data[0]).map((key: string, index: number) => {
          return key !== 'name' ? <Bar dataKey={key} key={key} fill={colors[(index - 1) % colors.length]} /> : null;
        })}
      </RechartsBarChart>
    </ResponsiveContainer>
  );
}
Example #11
Source File: TrafficChart.tsx    From web-show with Apache License 2.0 6 votes vote down vote up
TrafficChart: React.FC<IProps> = props => {
  const { data } = props;
  return (
    <ResponsiveContainer>
      <ComposedChart
        barGap="2%"
        width={600}
        height={400}
        margin={{
          top: 10,
          right: 30,
          left: 20,
          bottom: 20
        }}
        data={data}
      >
        <CartesianGrid strokeDasharray="3 3" />

        <XAxis
          tickLine={false}
          dataKey="time"
          domain = {['auto', 'auto']}
          tickFormatter = {(unixTime) => moment(unixTime).format('HH:mm:ss Do')}
          type = 'number'
        />
        <YAxis label={{ value: 'Latency', position: 'insideLeft', angle: -90 }} unit={"ms"}/>
        <Tooltip labelFormatter={t => new Date(t).toLocaleString()} />
        <Legend />
        <Line type="monotone" dataKey="latency" stroke="#8884d8" />
      </ComposedChart>
    </ResponsiveContainer>
  );
}
Example #12
Source File: BuildTimeline.tsx    From backstage with Apache License 2.0 6 votes vote down vote up
BuildTimeline = ({
  targets,
  height,
  width,
}: BuildTimelineProps) => {
  const theme = useTheme();
  if (!targets.length) return <p>No Targets</p>;

  const data = getTimelineData(targets);

  return (
    <ResponsiveContainer
      height={height}
      width={width}
      minHeight={EMPTY_HEIGHT + targets.length * 5}
    >
      <BarChart layout="vertical" data={data} maxBarSize={10} barGap={0}>
        <CartesianGrid strokeDasharray="2 2" />
        <XAxis type="number" domain={[0, 'dataMax']} />
        <YAxis type="category" dataKey="name" padding={{ top: 0, bottom: 0 }} />
        <Tooltip content={<TargetToolTip />} />
        <Legend />
        <Bar
          dataKey="buildTime"
          fill={theme.palette.grey[400]}
          minPointSize={1}
        />
        <Bar dataKey="compileTime" fill={theme.palette.primary.main} />
      </BarChart>
    </ResponsiveContainer>
  );
}
Example #13
Source File: WeeklyIncidentsSeverity.tsx    From backstage-plugin-opsgenie with MIT License 6 votes vote down vote up
Graph = ({context}: {context: Context}) => {
    const analyticsApi = useApi(analyticsApiRef);
    const dataPoints = analyticsApi.incidentsByWeekAndSeverity(context);

    return (
        <div id="weekly-incidents-severity" style={{ width: '100%', height: 300, paddingTop: '1.2rem', paddingRight: '1.2rem' }}>
            <ResponsiveContainer>
                <ComposedChart data={dataPoints}>
                    <CartesianGrid strokeDasharray="3 3" />
                    <XAxis dataKey="week" />
                    <YAxis />
                    <Bar dataKey="p1" fill="#bf2600" name="P1 - Critical" stackId="a" barSize={30} />
                    <Bar dataKey="p2" fill="#ff7452" name="P2 - High" stackId="a" barSize={30} />
                    <Bar dataKey="p3" fill="#ffab00" name="P3 - Moderate" stackId="a" barSize={30} />
                    <Bar dataKey="p4" fill="#36b37e" name="P4 - Low" stackId="a" barSize={30} />
                    <Bar dataKey="p5" fill="#00857A" name="P5 - Informational" stackId="a" barSize={30} />
                    <Tooltip content={<FilterZeroTooltip />} />
                    <Legend />
                </ComposedChart>
            </ResponsiveContainer>
        </div>
    );
}
Example #14
Source File: WeeklyIncidents.tsx    From backstage-plugin-opsgenie with MIT License 6 votes vote down vote up
Graph = ({context}: {context: Context}) => {
    const analyticsApi = useApi(analyticsApiRef);
    const dataPoints = analyticsApi.incidentsByWeekAndHours(context);

    return (
        <div id="weekly-incidents" style={{ width: '100%', height: 300, paddingTop: '1.2rem', paddingRight: '1.2rem' }}>
            <ResponsiveContainer>
                <ComposedChart
                    data={dataPoints}
                >
                    <CartesianGrid strokeDasharray="3 3" />
                    <XAxis dataKey="week" />
                    <YAxis />
                    <Bar dataKey="businessHours" fill="#82ca9d" name="Business hours" stackId="a" barSize={30} />
                    <Bar dataKey="onCallHours" fill="#8884d8" name="On-call hours" stackId="a" barSize={30} />
                    <Line type="monotone" dataKey="total" name="Total" stroke="#ff7300" />
                    <Tooltip content={<FilterZeroTooltip />} />
                    <Legend />
                </ComposedChart>
            </ResponsiveContainer>
        </div>
    );
}
Example #15
Source File: WeeklyImpactResponder.tsx    From backstage-plugin-opsgenie with MIT License 6 votes vote down vote up
WeeklyImpactResponders = ({ context }: { context: Context }) => {
    const graphId = "weekly-impact-responders";
    const analyticsApi = useApi(analyticsApiRef);
    const data = analyticsApi.impactByWeekAndResponder(context);

    return (
        <InfoCard title="Average impact by week and responder" action={<SaveAction targetRef={graphId} />}>
            <div id={graphId} style={{ width: '100%', height: 450, paddingTop: '1.2rem', paddingRight: '1.2rem' }}>
                <ResponsiveContainer>
                    <ComposedChart data={data.dataPoints}>
                        <CartesianGrid strokeDasharray="3 3" />

                        <XAxis dataKey="period" />
                        <YAxis tickFormatter={value => value === 0 ? '0 min' : moment.duration(value, 'minutes').humanize()} />

                        {data.responders.map(responder => (
                            <Bar dataKey={responder} fill={colorForString(responder)} stackId="a" barSize={30} key={responder} />
                        ))}

                        <Tooltip
                            formatter={(value: number, name: string) => [value === 0 ? '0 min' : moment.duration(value, 'minutes').humanize(), name]}
                            content={<FilterZeroTooltip />}
                        />
                        <Legend />
                    </ComposedChart>
                </ResponsiveContainer>
            </div>
        </InfoCard>
    );
}
Example #16
Source File: index.tsx    From Demae with MIT License 6 votes vote down vote up
OrderChart = () => {
	return (
		<LineChart
			width={500}
			height={300}
			data={data}
			margin={{
				top: 5, right: 30, left: 20, bottom: 5,
			}}
		>
			<CartesianGrid strokeDasharray="3 3" />
			<XAxis dataKey="name" />
			<YAxis />
			<Tooltip />
			<Legend />
			<Line type="monotone" dataKey="pv" stroke="#8884d8" activeDot={{ r: 8 }} />
			<Line type="monotone" dataKey="uv" stroke="#82ca9d" />
		</LineChart>
	);
}
Example #17
Source File: stats.tsx    From config-generator with MIT License 5 votes vote down vote up
public render() {
    const { stats, onRefresh, range } = this.props;
    const { strokeWidth } = this.state;
    return (
      <ResponsiveContainer width="100%" maxHeight={500} aspect={4.0 / 3.0}>
        <LineChart
          data={stats}
          margin={{
            top: 25,
            right: 30,
            left: 20,
            bottom: 100,
          }}
        >
          <CartesianGrid strokeDasharray="1 4" />
          <XAxis
            dataKey="timeStamp"
            tick={this.renderCustomAxisTick}
            interval={0}
            ticks={stats.map((s: any) => s.timeStamp)}
            type="number"
            domain={['dataMin', 'dataMax']}
          />
          <YAxis />
          <Tooltip
            itemStyle={{ textTransform: 'capitalize' }}
            labelFormatter={value =>
              range === 'day'
                ? moment(value).format('DD/MM/YYYY HH:mm:ss')
                : moment(value).format('DD/MM/YYYY')
            }
            labelStyle={{ fontWeight: 'bold', marginBottom: '10px' }}
          />
          <Legend
            verticalAlign="top"
            iconType="circle"
            formatter={(value, entry, index) => value.toUpperCase()}
            onMouseEnter={this.handleMouseEnter}
            onMouseLeave={this.handleMouseLeave}
          />
          <Line
            type="monotone"
            dataKey="all"
            connectNulls={true}
            stroke="#4F4F4F"
            activeDot={{ r: 8 }}
            strokeWidth={strokeWidth.all}
          />
          <Line
            type="monotone"
            dataKey="allowed"
            stroke="#71ADFE"
            connectNulls={true}
            activeDot={{ r: 8 }}
            strokeWidth={strokeWidth.allowed}
          />
          <Line
            type="monotone"
            connectNulls={true}
            dataKey="blocked"
            stroke="#EB5757"
            activeDot={{ r: 8 }}
            strokeWidth={strokeWidth.blocked}
          />
        </LineChart>
      </ResponsiveContainer>
    );
  }
Example #18
Source File: PoolComposition.tsx    From mStable-apps with GNU Lesser General Public License v3.0 5 votes vote down vote up
PoolComposition: FC = () => {
  const { masset, fasset } = useSelectedFeederPoolState()

  const data = useMemo(
    () => [
      {
        name: masset.token.symbol,
        value: masset.totalVaultInMasset.simple,
        fill: assetColorMapping[masset.token.symbol] ?? '#444',
      },
      {
        name: fasset.token.symbol,
        value: fasset.totalVaultInMasset.simple,
        fill: assetColorMapping[fasset.token.symbol] ?? '#888',
      },
    ],
    [masset, fasset],
  )

  return (
    <RechartsContainer>
      <ResponsiveContainer aspect={2}>
        <PieChart margin={MARGIN}>
          <Pie dataKey="value" isAnimationActive={false} data={data} fill="fill" />
          <Legend align="left" layout="vertical" verticalAlign="middle" />
          <Tooltip
            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,
            }}
          />
        </PieChart>
      </ResponsiveContainer>
    </RechartsContainer>
  )
}
Example #19
Source File: QueueMetricsChart.tsx    From asynqmon with MIT License 5 votes vote down vote up
function QueueMetricsChart(props: Props) {
  const theme = useTheme();

  const data = toChartData(props.data);
  const keys = props.data.map((x) => x.metric.queue);
  return (
    <ResponsiveContainer height={260}>
      <LineChart data={data}>
        <CartesianGrid strokeDasharray="3 3" />
        <XAxis
          minTickGap={10}
          dataKey="timestamp"
          domain={[props.startTime, props.endTime]}
          tickFormatter={(timestamp: number) =>
            new Date(timestamp * 1000).toLocaleTimeString()
          }
          type="number"
          scale="time"
          stroke={theme.palette.text.secondary}
        />
        <YAxis
          tickFormatter={props.yAxisTickFormatter}
          stroke={theme.palette.text.secondary}
        />
        <Tooltip
          labelFormatter={(timestamp: number) => {
            return new Date(timestamp * 1000).toLocaleTimeString();
          }}
        />
        <Legend />
        {keys.map((key, idx) => (
          <Line
            key={key}
            type="monotone"
            dataKey={key}
            stroke={lineColors[idx % lineColors.length]}
            dot={false}
          />
        ))}
      </LineChart>
    </ResponsiveContainer>
  );
}
Example #20
Source File: StatisticsChart.tsx    From jitsu with MIT License 5 votes vote down vote up
StatisticsChart: React.FC<Props> = ({
  data,
  granularity,
  dataToDisplay = ["success", "skip", "errors"],
  legendLabels = {},
}) => {
  const [state, dispatch] = useReducer(reducer, initialState)

  const handleClickOnLegend = (data: any) => {
    const clickedDataType = data["value"] as DataType
    dispatch({ type: clickedDataType })
  }

  return (
    <ResponsiveContainer width="100%" minHeight={225} minWidth={300}>
      <LineChart
        className={styles.chart}
        data={data.map(point => ({
          ...point,
          date: granularity == "hour" ? point.date.format("HH:mm") : point.date.format("DD MMM"),
        }))}
      >
        <XAxis dataKey="date" tick={<CustomizedXAxisTick />} stroke="#394e5a" />
        <YAxis tick={<CustomizedYAxisTick />} stroke="#394e5a" />
        <CartesianGrid strokeDasharray="3 3" stroke="#394e5a" />
        <Legend onClick={handleClickOnLegend} formatter={value => legendLabels[value] ?? value} />
        <Tooltip
          wrapperStyle={{
            backgroundColor: "#22313a",
            border: "1px solid #394e5a",
          }}
          itemStyle={{ color: "#9bbcd1" }}
          labelStyle={{ color: "#dcf3ff" }}
          formatter={value => new Intl.NumberFormat("en").format(value)}
        />
        {dataToDisplay.includes("total") && (
          <Line dataKey="total" stroke={"rgb(135, 138, 252)"} hide={state.hide_total_data} {...commonLineProps} />
        )}
        {dataToDisplay.includes("success") && (
          <Line dataKey="success" stroke={"#2cc56f"} hide={state.hide_success_data} {...commonLineProps} />
        )}
        {dataToDisplay.includes("skip") && (
          <Line dataKey="skip" stroke={"#ffc021"} hide={state.hide_skip_data} {...commonLineProps} />
        )}
        {dataToDisplay.includes("errors") && (
          <Line dataKey="errors" stroke={"#e53935"} hide={state.hide_errors_data} {...commonLineProps} />
        )}
      </LineChart>
    </ResponsiveContainer>
  )
}
Example #21
Source File: index.tsx    From korona-info with MIT License 4 votes vote down vote up
Index: NextPage<{ groupedCoronaData: GroupedData, hospitalised: HospitalData[] }> = ({
  groupedCoronaData, hospitalised
}: {
  groupedCoronaData: GroupedData;
  hospitalised: HospitalData[];
}) => {
  const [selectedHealthCareDistrict, selectHealthCareDistrict] = useState<
    string
  >('all');
  const confirmed = groupedCoronaData[selectedHealthCareDistrict].confirmed;
  const deaths = groupedCoronaData[selectedHealthCareDistrict].deaths;
  const recovered = groupedCoronaData[selectedHealthCareDistrict].recovered;
  const allConfirmed = groupedCoronaData.all.confirmed;
  const toast = useToast()
  const latestInfection = confirmed.length
    ? format(
      utcToZonedTime(
        new Date(confirmed[confirmed.length - 1].date),
        timeZone
      ),
      'dd.MM.yyyy - HH:mm',
      { timeZone }
    )
    : null;
  const latestInfectionDistrict =
    confirmed[confirmed.length - 1]?.healthCareDistrict;
  const latestDeath = deaths.length
    ? format(
      utcToZonedTime(new Date(deaths[deaths.length - 1].date), timeZone),
      'd.M.yyyy'
    )
    : null;
  const latestDeathDistrict = deaths.length
    ? deaths[deaths.length - 1].area
    : null;
  const latestRecoveredDistrict = recovered.length
    ? recovered[recovered.length - 1].healthCareDistrict
    : null;
  const latestRecovered = recovered.length
    ? format(
      utcToZonedTime(
        new Date(recovered[recovered.length - 1].date),
        timeZone
      ),
      'd.M.yyyy'
    )
    : null;
  const infectionsToday = getInfectionsToday(confirmed);

  const [cumulativeChartScale, setCumulativeChartScale] = useState<
    'linear' | 'log'
  >('linear');
  const [forecastChartScale, setForecaseChartScale] = useState<
    'linear' | 'log'
  >('linear');
  // Map data to show development of infections
  const {
    infectionDevelopmentData,
    infectionDevelopmentData30Days
  } = groupedCoronaData[selectedHealthCareDistrict].timeSeries;
  const maxValues =
    infectionDevelopmentData30Days[infectionDevelopmentData30Days.length - 1];
  const dataMaxValue = Math.max(
    maxValues?.deaths ?? 0,
    maxValues?.infections ?? 0,
    maxValues?.infections ?? 0
  );

  const {
    infectionsByDistrict,
    infectionsByDistrictPercentage,
    areas
  } = getTnfectionsByDistrict(allConfirmed);
  const { infectionsBySourceCountry } = getInfectionsBySourceCountry(confirmed);
  const networkGraphData = getNetworkGraphData(confirmed);

  const { t } = useContext(UserContext);

  const humanizeHealthcareDistrict = (district: string) => {
    if (district === 'all') {
      return t('All healthcare districts');
    } else if (district === 'unknown') {
      return t('unknown');
    } else {
      return district;
    }
  };

  const reversedConfirmed = confirmed
    // @ts-ignore
    .map((i, index) => ({
      index: index + 1,
      ...i,
      healthCareDistrict: humanizeHealthcareDistrict(i.healthCareDistrict)
    }))
    .reverse();

  const humanizedHealthCareDistrict = humanizeHealthcareDistrict(
    selectedHealthCareDistrict
  );
  useEffect(() => {
    if (typeof window !== undefined) {

      toast({
        position: 'bottom',
        title: 'Datan lähteenä nyt THL',
        description: 'HS:n datan lähde on vaihtunut THL:ään. THL:n tiedotussyklistä johtuen tiedot päivittyvät aiempaa harvemmin. Myös vanhemmissa tapauksissa voi olla päivämääräkohtaisia eroja, johtuen muuttuneesta raportointitavasta.',
        status: "info",
        isClosable: true,
        duration: 14000,
      });




    }

  }, [])

  return (
    <>
      <Head>
        <title>
          {t('finland corona status')} - {t('cases')} : {confirmed.length || 0}{' '}
          - {t('recovered')}: {recovered.length || 0} - {t('deaths')}:{' '}
          {deaths.length || 0}
        </title>
        <meta
          name="description"
          content={`Suomen koronavirus-tartuntatilanne – tartunnat: ${confirmed.length ||
            0} - parantuneet: ${recovered.length ||
            0} - menehtyneet: ${deaths.length || 0}`}
        />
        <meta property="og:title" content={t('finland corona status')} />
        <meta
          property="og:description"
          content={`Tartuntoja tällä hetkellä: ${confirmed.length ||
            0} - parantuneet: ${recovered.length ||
            0} - menehtyneet: ${deaths.length || 0}`}
        />
        <meta
          property="og:site_name"
          content="Suomen koronavirus-tartuntatilanne"
        />
        <meta property="og:locale" content="fi_FI" />
        <meta property="og:type" content="website" />
        <meta property="og:image" content="/images/corona-virus.png" />
        <meta property="og:image:width" content="1920" />
        <meta property="og:image:height" content="1928" />
        <meta property="og:url" content="https://korona.kans.io" />
      </Head>
      <Layout>

        <Flex
          alignItems="center"
          flexDirection="column"
          flex="1"
          width={'100%'}
          maxWidth="1440px"
          margin="auto"
        >
          <Header />
          <Flex
            flexWrap="wrap"
            flexDirection="row"
            justifyContent="left"
            alignItems="stretch"
            flex="1"
            width={'100%'}
          >
            <Box width={['100%', '100%', 1 / 3, 1 / 3]} p={3}>
              <Select
                value={selectedHealthCareDistrict ?? undefined}
                onChange={event => selectHealthCareDistrict(event.target.value)}
              >
                <option key={'all'} value={'all'}>
                  {t('All healthcare districts')}
                </option>
                {healtCareDistricts.map(healthcareDistrict => (
                  <option
                    key={healthcareDistrict.name}
                    value={healthcareDistrict.name}
                  >
                    {healthcareDistrict.name}
                  </option>
                ))}
              ))}
            </Select>
            </Box>
          </Flex>
          <Flex
            flexWrap="wrap"
            flexDirection="row"
            justifyContent="center"
            alignItems="stretch"
            flex="1"
            width={'100%'}
          >
            <Box width={['100%', '100%', 1 / 2, 1 / 2]} p={3}>
              <Block
                title={t('cases') + ` (${humanizedHealthCareDistrict})`}
                textAlign="center"
                extraInfo={`${t('New cases today')} ${infectionsToday} ${t(
                  'person'
                )}`}
                footer={`${t(
                  'latest case'
                )} ${latestInfection} (${humanizeHealthcareDistrict(
                  latestInfectionDistrict
                )})`}
              >
                <StatBlock
                  count={confirmed.length}
                  helpText={`${t('New cases today')}: ${infectionsToday} ${t(
                    'person'
                  )}`}
                />
              </Block>
            </Box>
            <Box width={['100%', '100%', 1 / 2, 1 / 2]} p={3}>
              <Block
                title={t('deaths') + ` (${humanizedHealthCareDistrict})`}
                footer={
                  latestDeath
                    ? `${t(
                      'last death'
                    )} ${latestDeath} (${humanizeHealthcareDistrict(
                      latestDeathDistrict!
                    )})`
                    : t('no death')
                }
              >
                <StatBlock count={deaths.length || 0} />
              </Block>
            </Box>
            {/* <Box width={['100%', '100%', 1 / 3, 1 / 3]} p={3}>
              <Block
                title={t('recovered') + ` (${humanizedHealthCareDistrict})`}
                footer={
                  `${latestRecovered
                    ? `${t(
                      'latest recovery'
                    )} ${latestRecovered} (${humanizeHealthcareDistrict(latestRecoveredDistrict!)}).`
                    : ' '} ${t('recoveredNotice')}`}
              >
                <StatBlock count={recovered.length || 0} />
              </Block>
            </Box> */}

            <Box width={['100%']} p={3}>
              <Block
                title={
                  t('accumulated change') + ` (${humanizedHealthCareDistrict})`
                }
                footer={t('cases recovered and death in past 30 days')}
              >
                <ButtonGroup
                  spacing={0}
                  alignSelf="center"
                  display="flex"
                  justifyContent="center"
                  marginTop="-15px"
                >
                  <Button
                    size="xs"
                    fontFamily="Space Grotesk Regular"
                    px={3}
                    letterSpacing="1px"
                    borderRadius="4px 0px 0px 4px"
                    borderWidth="0px"
                    isActive={cumulativeChartScale === 'linear'}
                    onClick={() => setCumulativeChartScale('linear')}
                  >
                    {t('linear')}
                  </Button>
                  <Button
                    size="xs"
                    fontFamily="Space Grotesk Regular"
                    px={3}
                    letterSpacing="1px"
                    borderRadius="0px 4px 4px 0px"
                    borderWidth="0px"
                    isActive={cumulativeChartScale === 'log'}
                    onClick={() => setCumulativeChartScale('log')}
                  >
                    {t('logarithmic')}
                  </Button>
                </ButtonGroup>
                <ResponsiveContainer width={'100%'} height={380}>
                  <ComposedChart
                    data={
                      cumulativeChartScale === 'log'
                        ? infectionDevelopmentData30Days.map(zerosToNulls)
                        : infectionDevelopmentData30Days
                    }
                    margin={{ top: 20, right: 30, left: 0, bottom: 30 }}
                  >
                    <defs>
                      <linearGradient
                        id="colorInfection"
                        x1="0"
                        y1="0"
                        x2="0"
                        y2="1"
                      >
                        <stop
                          offset="5%"
                          stopColor={colors[8]}
                          stopOpacity={0.6}
                        />
                        <stop
                          offset="95%"
                          stopColor={colors[8]}
                          stopOpacity={0}
                        />
                      </linearGradient>
                      <linearGradient
                        id="colorRecovered"
                        x1="0"
                        y1="0"
                        x2="0"
                        y2="1"
                      >
                        <stop
                          offset="5%"
                          stopColor={colors[7]}
                          stopOpacity={0.6}
                        />
                        <stop
                          offset="95%"
                          stopColor={colors[7]}
                          stopOpacity={0}
                        />
                      </linearGradient>
                      <linearGradient
                        id="colorDeaths"
                        x1="0"
                        y1="0"
                        x2="0"
                        y2="1"
                      >
                        <stop
                          offset="5%"
                          stopColor={colors[0]}
                          stopOpacity={0.6}
                        />
                        <stop
                          offset="95%"
                          stopColor={colors[0]}
                          stopOpacity={0}
                        />
                      </linearGradient>
                    </defs>
                    <XAxis
                      tickFormatter={d => format(new Date(d), 'd.M.')}
                      tick={<CustomizedAxisTick isDate />}
                      dataKey="date"
                      domain={['dataMin', 'dataMax']}
                      type="number"
                      scale="time"
                    />
                    <YAxis
                      scale={cumulativeChartScale}
                      dataKey="infections"
                      domain={[
                        cumulativeChartScale === 'log' ? 1 : 0,
                        dataMaxValue + 10
                      ]}
                      unit={' ' + t('person')}
                      tick={{ fontSize: 12 }}
                      name={t('cases')}
                    />
                    <CartesianGrid opacity={0.2} />
                    <Tooltip
                      labelFormatter={v => format(new Date(v), 'dd.MM.yyyy')}
                    />
                    <Bar
                      isAnimationActive={false}
                      fill={colors[1]}
                      opacity={0.4}
                      dataKey="infectionsDaily"
                      name={t('cases of the day')}
                      unit={' ' + t('person')}
                    />
                    <Area
                      isAnimationActive={false}
                      type="monotone"
                      unit={' ' + t('person')}
                      name={t('total cases')}
                      dataKey="infections"
                      stroke={colors[8]}
                      fillOpacity={1}
                      fill="url(#colorInfection)"
                    />
                    {/* <Area
                      isAnimationActive={false}
                      type="monotone"
                      unit={' ' + t('person')}
                      name={t('total recovered')}
                      dataKey="recovered"
                      stroke={colors[7]}
                      fillOpacity={1}
                      fill="url(#colorRecovered)"
                    /> */}
                    <Area
                      isAnimationActive={false}
                      type="monotone"
                      unit={' ' + t('person')}
                      name={t('total deaths')}
                      dataKey="deaths"
                      stroke={colors[0]}
                      fillOpacity={1}
                      fill="url(#colorDeaths)"
                    />
                    <Legend wrapperStyle={{ bottom: '10px' }} />
                  </ComposedChart>
                </ResponsiveContainer>
              </Block>
            </Box>
            {/*
          <Box width={['100%']} p={3}>
            <Block title="Tartuntojen kumulatiivinen ennustemalli" footer={`Tartuntojen kehityksen ennustemalli 60 päivää. Laskee ennustetun eksponentiaalisen kasvun käyttämällä aiemmin luotuja tietoja.  Käytetty <a style="color: #319795;" href="https://github.com/mljs/regression-exponential" target="_blank">exponential-regression</a> kirjastoa.`}>
              <ButtonGroup spacing={0} alignSelf="center" display="flex" justifyContent="center" marginTop="-15px">
                <Button size="xs" fontFamily="Space Grotesk Regular" px={3} letterSpacing="1px" borderRadius="4px 0px 0px 4px" borderWidth="0px" isActive={forecastChartScale === 'linear'} onClick={() => setForecaseChartScale('linear')}>
                  Lineaarinen
                </Button>
                <Button size="xs" fontFamily="Space Grotesk Regular" px={3} letterSpacing="1px" borderRadius="0px 4px 4px 0px" borderWidth="0px" isActive={forecastChartScale === 'log'}  onClick={() => setForecaseChartScale('log')}>
                  Logaritminen
                </Button>
              </ButtonGroup>
              <ResponsiveContainer width={'100%'} height={350}>
                <AreaChart
                    data={prediction60Days}
                    margin={{ top: 20, right: 30, left: 0, bottom: 20 }}
                >
                  <defs>
                    <linearGradient id="colorInfection" x1="0" y1="0" x2="0" y2="1">
                      <stop offset="5%" stopColor={colors[8]} stopOpacity={0.6} />
                      <stop offset="95%" stopColor={colors[8]} stopOpacity={0} />
                    </linearGradient>
                  </defs>
                  <XAxis tickFormatter={d => format(new Date(d), 'd.M.')} tick={<CustomizedAxisTick isDate />} dataKey="date" domain={['dataMin', 'dataMax']} type="number" scale="time" />
                  <YAxis scale={forecastChartScale} dataKey="infections" domain={['auto', 'auto']} unit={' ' + t('person') } tick={{ fontSize: 12 }} name="Tartunnat" />

                  <CartesianGrid opacity={0.2} />
                  <ReferenceLine
                    x={today}
                    stroke="rgba(0,0,0,.5)"
                    // @ts-ignore
                    label={{ position: 'top', value: 'Nyt', fill: 'rgba(0,0,0,0.5)', fontSize: 12 }}
                    strokeDasharray="3 3" />
                  <Tooltip labelFormatter={v => format(new Date(v), 'dd.MM.yyyy')} />
                  <Area type="monotone" name="Ennuste" unit={' ' + t('person') } dataKey="infections" stroke={colors[8]} fillOpacity={1} fill="url(#colorInfection)" />
                </AreaChart>
              </ResponsiveContainer>
            </Block>
          </Box>
           */}
            <Box width={['100%', '100%', '100%', '100%', 1 / 2]} p={3}>
              <Block
                title={t('Cases by district')}
                footer={t('Helsinki metropolitan area is shown as HUS')}
              >
                <ResponsiveContainer width={'100%'} height={350}>
                  <BarChart
                    data={infectionsByDistrict}
                    margin={{
                      top: 20,
                      right: 30,
                      left: 0,
                      bottom: 85
                    }}
                  >
                    <XAxis
                      interval={0}
                      dataKey="name"
                      tick={<CustomizedAxisTick />}
                    />
                    <YAxis
                      yAxisId="left"
                      unit={' ' + t('person')}
                      dataKey="infections"
                      tick={{ fontSize: 12 }}
                    />
                    <Tooltip />
                    <Bar
                      isAnimationActive={false}
                      dataKey="infections"
                      name={t('cases')}
                      unit={' ' + t('person')}
                      yAxisId="left"
                    >
                      {areas.map((area, index) => (
                        <Cell key={area} fill={colors[index % colors.length]} />
                      ))}
                      <LabelList
                        dataKey="infections"
                        position="top"
                        formatter={e => e}
                      />
                    </Bar>
                  </BarChart>
                </ResponsiveContainer>
              </Block>
            </Box>
            <Box width={['100%', '100%', '100%', '100%', 1 / 2]} p={3}>
              <Block
                title={t('infectionsPerDisrictAndSize')}
                footer={t('infectionsPerDisrictAndSize')}
              >
                <ResponsiveContainer width={'100%'} height={350}>
                  <BarChart
                    data={infectionsByDistrictPercentage}
                    margin={{
                      top: 20,
                      right: 30,
                      left: 0,
                      bottom: 85
                    }}
                  >
                    <XAxis
                      interval={0}
                      dataKey="name"
                      tick={<CustomizedAxisTick />}
                    />
                    <YAxis
                      unit=" %"
                      dataKey="perDistrict"
                      tick={{ fontSize: 12 }}
                    />
                    <Tooltip />
                    <Bar isAnimationActive={false} dataKey="perDistrict" name="%-osuus väestöstä" unit=" %">
                      {areas.map((area, index) => (
                        <Cell key={area} fill={colors[index % colors.length]} />
                      ))}
                      <LabelList
                        dataKey="perDistict"
                        position="top"
                        formatter={e => e}
                      />
                    </Bar>
                  </BarChart>
                </ResponsiveContainer>
              </Block>
            </Box>
            <Box width={['100%', '100%', '100%', '100%', 1 / 2]} p={3}>
              <Block
                title={t('log') + ` (${humanizedHealthCareDistrict})`}
                footer={t('logFooter')}
              >
                <Table
                  height={500}
                  data={reversedConfirmed}
                  columns={useMemo(() => infectionColumns, [])}
                />
              </Block>
            </Box>
            <BubbleChart data={groupedCoronaData} />
            {/* <Box width={['100%', '100%', '100%', '100%', 1 / 2]} p={3}>
              <Block
                title={
                  t('infectionNetwork') + ` (${humanizedHealthCareDistrict})`
                }
                footer={t('infectionNetworkFooter')}
              >
                <NetworkGraph data={networkGraphData} />
              </Block>
            </Box> */}
            <Box width={['100%']} p={3}>
              <Block
                title={
                  t('hospitalizedData') + ` (${t('All healthcare districts')})`
                }
              >
                <ResponsiveContainer width={'100%'} height={350}>
                  <BarChart
                    data={hospitalised.slice(Math.max(hospitalised.length - 30, 0))}
                    margin={{
                      top: 20,
                      right: 30,
                      left: 0,
                      bottom: 85
                    }}
                  >
                    <XAxis
                      interval={0}
                      dataKey="dateString"
                      tick={<CustomizedAxisTick />}
                      padding={{ left: 50, right: 50 }}
                    />
                    <YAxis
                      unit={' ' + t('person')}
                      dataKey="totalHospitalised"
                      tick={{ fontSize: 12 }}
                    />
                    <Tooltip />
                    <Bar
                      isAnimationActive={false}
                      stackId="a"
                      dataKey="inIcu"
                      name={t("inIcu")}
                      unit={' ' + t('person')}
                      fill="#F3858D"
                    />
                    <Bar
                      isAnimationActive={false}
                      stackId="a"
                      dataKey="inWard"
                      name={t("inWard")}
                      unit={' ' + t('person')}
                      fill="#2FAB8E"
                    />

                    <Bar
                      isAnimationActive={false}
                      stackId="a"
                      dataKey="totalHospitalised"
                      opacity={0}
                      name={t("inHospital")}
                      unit={' ' + t('person')}
                      fill="rgba(0,0,0,1)"
                      strokeWidth={0}
                      legendType="none"
                    />
                    <Legend wrapperStyle={{ bottom: '15px' }} />
                  </BarChart>
                </ResponsiveContainer>
              </Block>
            </Box>

          </Flex>

          <Copyright />
        </Flex>
      </Layout>
    </>
  );
}
Example #22
Source File: index.tsx    From livepeer-com with MIT License 4 votes vote down vote up
Chart = ({
  data,
  multiData,
}: {
  data: Array<{ name: number; "Session bitrate": number }>;
  multiData?: Array<{
    [name: string]: number;
  }>;
}) => {
  const multistreamNames =
    multiData && multiData[0] && Object.keys(multiData[0]);
  return (
    <Box
      css={{
        width: "100%",
        position: "relative",
        ".recharts-cartesian-axis-tick": {
          fontSize: "$2",
        },
      }}>
      <Text
        variant="gray"
        size="1"
        css={{
          transform: "rotate(-90deg)",
          position: "absolute",
          left: "-70px",
          bottom: "70px",
        }}>
        kbps (multiplied by 1000)
      </Text>
      <Text
        variant="gray"
        size="1"
        css={{
          position: "absolute",
          bottom: "-30px",
          left: "50px",
        }}>
        Seconds since stream loaded
      </Text>
      <ResponsiveContainer width="99%" height={300}>
        <LineChart>
          <XAxis
            type="number"
            dataKey="name"
            domain={[
              data[0]?.name,
              data.length < 2 ? 10 : data[data.length - 1].name,
            ]}
            tickCount={7}
            allowDataOverflow
          />
          <YAxis domain={[0, 1600]} />
          <CartesianGrid vertical={false} />
          <Tooltip content={<CustomTooltip />} />
          <Legend wrapperStyle={{ fontSize: "10px" }} />
          <Line
            data={data}
            cursor="pointer"
            type="monotone"
            dataKey="Session bitrate"
            stroke="#5746AF"
            strokeWidth="2px"
          />
          {multistreamNames?.map((item, index) => {
            if (item !== "name")
              return (
                <Line
                  data={multiData}
                  cursor="pointer"
                  type="monotone"
                  dataKey={item}
                  stroke={getMultistreamColor(index)}
                  strokeWidth="2px"
                />
              );
          })}
        </LineChart>
      </ResponsiveContainer>
    </Box>
  );
}
Example #23
Source File: index.tsx    From liferay-grow with MIT License 4 votes vote down vote up
SkillDetailSummay: React.FC<SkillDetailSummaryProps> = ({
  slug,
  summary,
}) => {
  const i18n = useLang();
  const [visible, setVisible] = useState(false);
  const [matriz, setMatriz] = useState<Summary>({} as Summary);

  const { observer, onClose } = useModal({
    onClose: () => setVisible(!visible),
  });

  // Filter Empty Results from Summary

  const summaryData = summary.filter(({ value }) => value);

  const getFromattedTooltip = (value: number) => {
    const valueString = value.toString();

    return i18n.sub(value > 1 ? 'x-members' : 'x-member', valueString);
  };

  const hasSummary = !!summaryData.length;

  return (
    <Panel displayType="unstyled" title={i18n.get('summary')}>
      {hasSummary ? (
        <>
          <PieChart className="summary-chart" width={420} height={280}>
            <Pie
              data={summaryData}
              dataKey="value"
              nameKey="name"
              cx="50%"
              cy="50%"
              innerRadius={70}
              outerRadius={120}
              paddingAngle={0}
            >
              {summary.map((_, index) => (
                <Cell
                  key={index}
                  fill={COLORS[index]}
                  onClick={() => console.log(summary)}
                />
              ))}
            </Pie>
            <Tooltip formatter={getFromattedTooltip} />
            <Legend
              align="right"
              iconSize={16}
              formatter={(value) => (
                <ClayButton
                  displayType="unstyled"
                  onClick={() => {
                    setVisible(true);
                    const matriz = summary.find(({ name }) => name === value);
                    setMatriz(matriz);
                  }}
                >
                  <span className="legend-text">{value}</span>
                </ClayButton>
              )}
              iconType="square"
              layout="vertical"
              verticalAlign="middle"
            />
          </PieChart>
          <Modal
            visible={visible}
            observer={observer}
            title={matriz.name}
            subtitle={
              matriz.description
                ? `${i18n.sub('description-x-x', [
                    matriz.name,
                    matriz.description,
                  ])}`
                : null
            }
          >
            <ListMembers onClose={onClose} matriz={matriz} slug={slug} />
          </Modal>
        </>
      ) : (
        <EmptyState title={i18n.get('there-are-no-members-yet')} />
      )}
    </Panel>
  );
}
Example #24
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 #25
Source File: BalanceHistoryGraph.tsx    From abrechnung with GNU Affero General Public License v3.0 4 votes vote down vote up
export default function BalanceHistoryGraph({ group, accountID }) {
    const theme: Theme = useTheme();
    const balanceHistory = useRecoilValue(accountBalanceHistory({ groupID: group.id, accountID: accountID }));
    const history = useHistory();

    const transactionMap = useRecoilValue(transactionByIDMap(group.id));
    const accountMap = useRecoilValue(accountByIDMap(group.id));

    const onClick = (evt) => {
        if (evt.activePayload.length > 0) {
            const payload = evt.activePayload[0].payload;
            if (payload.changeOrigin.type === "clearing") {
                history.push(`/groups/${group.id}/accounts/${payload.changeOrigin.id}`);
            } else {
                history.push(`/groups/${group.id}/transactions/${payload.changeOrigin.id}`);
            }
        }
    };

    const renderTooltip = ({ payload, label, active }) => {
        if (!active) {
            return null;
        }

        const changeOrigin = payload[0].payload.changeOrigin;

        const icon =
            changeOrigin.type === "clearing" ? (
                <ClearingAccountIcon color="primary" fontSize="small" />
            ) : transactionMap[changeOrigin.id].type === "purchase" ? (
                <PurchaseIcon color="primary" sx={{ fontSize: theme.typography.fontSize }} />
            ) : (
                <TransferIcon color="primary" fontSize="small" />
            );

        return (
            <Box
                sx={{
                    backgroundColor: theme.palette.background.paper,
                    borderColor: theme.palette.divider,
                    borderRadius: theme.shape.borderRadius,
                    borderWidth: "1px",
                    borderStyle: "solid",
                    padding: 2,
                }}
            >
                <div style={{ display: "flex", justifyContent: "space-between" }}>
                    <Typography variant="body1" component="span">
                        {DateTime.fromSeconds(payload[0].payload.date).toISODate()} {icon}
                    </Typography>
                    <Typography
                        component="span"
                        sx={{ color: (theme) => balanceColor(payload[0].value, theme), ml: 2 }}
                    >
                        {payload[0].value} {group.currency_symbol}
                    </Typography>
                </div>
                <Divider />
                {payload[0].payload.changeOrigin.type === "clearing" ? (
                    <Typography variant="body1">{accountMap[payload[0].payload.changeOrigin.id].name}</Typography>
                ) : (
                    <Typography variant="body1">
                        {transactionMap[payload[0].payload.changeOrigin.id].description}
                    </Typography>
                )}
            </Box>
        );
    };

    return (
        <ResponsiveContainer width="100%" height={300}>
            <LineChart
                width={730}
                height={250}
                onClick={onClick}
                data={balanceHistory}
                margin={{
                    top: 5,
                    right: 30,
                    left: 20,
                    bottom: 5,
                }}
            >
                <CartesianGrid strokeDasharray="3 3" />
                <XAxis
                    dataKey="date"
                    stroke={theme.palette.text.primary}
                    type="number"
                    tickFormatter={(unixTime) => DateTime.fromSeconds(unixTime).toISODate()}
                    domain={["dataMin", "dataMax"]}
                />
                <YAxis
                    tickFormatter={(value) => value.toFixed(2)}
                    type="number"
                    unit={group.currency_symbol}
                    stroke={theme.palette.text.primary}
                />
                <Tooltip content={renderTooltip} />
                <Legend />
                <Line type="stepAfter" dataKey="balance" />
            </LineChart>
        </ResponsiveContainer>
    );
}
Example #26
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 #27
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>
  );
}
Example #28
Source File: CoverageHistoryChart.tsx    From backstage with Apache License 2.0 4 votes vote down vote up
CoverageHistoryChart = () => {
  const { entity } = useEntity();
  const codeCoverageApi = useApi(codeCoverageApiRef);
  const {
    loading: loadingHistory,
    error: errorHistory,
    value: valueHistory,
  } = useAsync(
    async () =>
      await codeCoverageApi.getCoverageHistoryForEntity({
        kind: entity.kind,
        namespace: entity.metadata.namespace || 'default',
        name: entity.metadata.name,
      }),
  );
  const classes = useStyles();

  if (loadingHistory) {
    return <Progress />;
  }
  if (errorHistory) {
    return <ResponseErrorPanel error={errorHistory} />;
  } else if (!valueHistory) {
    return <Alert severity="warning">No history found.</Alert>;
  }

  if (!valueHistory.history.length) {
    return (
      <Card>
        <CardHeader title="History" />
        <CardContent>No coverage history found</CardContent>
      </Card>
    );
  }

  const oldestCoverage = valueHistory.history[0];
  const [latestCoverage] = valueHistory.history.slice(-1);

  const getTrendForCoverage = (type: Coverage) => {
    if (!oldestCoverage[type].percentage) {
      return 0;
    }
    return (
      ((latestCoverage[type].percentage - oldestCoverage[type].percentage) /
        oldestCoverage[type].percentage) *
      100
    );
  };

  const lineTrend = getTrendForCoverage('line');
  const branchTrend = getTrendForCoverage('branch');

  return (
    <Card>
      <CardHeader title="History" />
      <CardContent>
        <Box px={6} display="flex">
          <Box display="flex" mr={4}>
            {getTrendIcon(lineTrend, classes)}
            <Typography>
              Current line: {latestCoverage.line.percentage}%<br />(
              {Math.floor(lineTrend)}% change over {valueHistory.history.length}{' '}
              builds)
            </Typography>
          </Box>
          <Box display="flex">
            {getTrendIcon(branchTrend, classes)}
            <Typography>
              Current branch: {latestCoverage.branch.percentage}%<br />(
              {Math.floor(branchTrend)}% change over{' '}
              {valueHistory.history.length} builds)
            </Typography>
          </Box>
        </Box>
        <ResponsiveContainer width="100%" height={300}>
          <LineChart
            data={valueHistory.history}
            margin={{ right: 48, top: 32 }}
          >
            <CartesianGrid strokeDasharray="3 3" />
            <XAxis
              dataKey="timestamp"
              tickFormatter={formatDateToHuman}
              reversed
            />
            <YAxis dataKey="line.percentage" />
            <YAxis dataKey="branch.percentage" />
            <Tooltip labelFormatter={formatDateToHuman} />
            <Legend />
            <Line
              type="monotone"
              dataKey="branch.percentage"
              stroke="#8884d8"
            />
            <Line type="monotone" dataKey="line.percentage" stroke="#82ca9d" />
          </LineChart>
        </ResponsiveContainer>
      </CardContent>
    </Card>
  );
}
Example #29
Source File: InDepth.tsx    From backstage with Apache License 2.0 4 votes vote down vote up
export function InDepth() {
  const { releaseStats } = useReleaseStatsContext();
  const { averageReleaseTime, progress, releaseCommitPairs, run } =
    useGetReleaseTimes();

  const skipped =
    Object.keys(releaseStats.releases).length - releaseCommitPairs.length;

  return (
    <Box style={{ flex: 1 }}>
      <Box margin={1}>
        <Typography variant="h4">In-depth</Typography>
      </Box>

      <Box style={{ display: 'flex' }}>
        <Box margin={1} style={{ display: 'flex', flex: 1 }}>
          <Box>
            <Typography variant="h6">Release time</Typography>

            <Typography variant="body2">
              <strong>Release time</strong> is derived by comparing{' '}
              <i>createdAt</i> of the commits belonging to the first and last
              tag of each release. Releases without patches will have tags
              pointing towards the same commit and will thus be omitted. This
              project will omit {skipped} out of the total{' '}
              {Object.keys(releaseStats.releases).length} releases.
            </Typography>
          </Box>
        </Box>

        <Box
          margin={1}
          style={{ display: 'flex', flex: 1, flexDirection: 'column' }}
        >
          <Box>
            <Typography variant="h6">In numbers</Typography>

            <Typography variant="body2" color="textSecondary">
              <strong>Average release time</strong>:{' '}
              <AverageReleaseTime averageReleaseTime={averageReleaseTime} />
            </Typography>

            <Typography variant="body2" color="textSecondary">
              <strong>Lengthiest release</strong>:{' '}
              <LongestReleaseTime averageReleaseTime={averageReleaseTime} />
            </Typography>
          </Box>

          <Box marginTop={1}>
            {progress === 0 && (
              <MaterialTooltip
                title={`This action will send ~${
                  releaseCommitPairs.length * 2
                } requests`}
              >
                <Button
                  variant="contained"
                  color="secondary"
                  onClick={() => run()}
                  size="small"
                >
                  Crunch the numbers
                </Button>
              </MaterialTooltip>
            )}
          </Box>
        </Box>
      </Box>

      <Box marginTop={4}>
        <BarChart
          width={700}
          height={70 + averageReleaseTime.length * 22}
          data={
            averageReleaseTime.length > 0
              ? averageReleaseTime
              : [{ version: 'x.y.z', days: 0 }]
          }
          margin={{ top: 5, right: 30, left: 20, bottom: 5 }}
          layout="vertical"
        >
          <XAxis type="number" />
          <YAxis dataKey="version" type="category" />
          <Tooltip labelStyle={{ color: '#000', fontWeight: 'bold' }} />
          <Legend />
          <Bar dataKey="days" fill="#82ca9d" />
        </BarChart>

        {progress > 0 && progress < 100 && (
          <Box marginTop={1}>
            <LinearProgressWithLabel progress={progress} responseSteps={[]} />
          </Box>
        )}
      </Box>
    </Box>
  );
}