recharts#Tooltip TypeScript Examples

The following examples show how to use recharts#Tooltip. 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: SimpleLineChart.tsx    From react-tutorials with MIT License 7 votes vote down vote up
SimpleLineChart = (props: ISimpleLineChartProps) => {
  return (
    <>
      <LineChart
        width={500}
        height={300}
        data={props.data}
        margin={{
          top: 5,
          right: 30,
          left: 20,
          bottom: 5,
        }}
      >
        <CartesianGrid strokeDasharray="3 3" />
        <XAxis
          height={60}
          dataKey="date"
          // @ts-ignore
          tick={<CustomizedAxisTick />}
        />
        <YAxis
          // @ts-ignore
          tick={<CustomizedYAxisTick />}
        />
        <Tooltip />
        <Line type="monotone" dataKey="value" stroke="#8884d8" dot={<EmptyDot />} />
      </LineChart>
    </>
  )
}
Example #2
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 #3
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 #4
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 #5
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 #6
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 #7
Source File: Line.tsx    From your_spotify with GNU General Public License v3.0 6 votes vote down vote up
export default function Line<
  D extends { x: number; y: number; dateWithPrecision: DateWithPrecision },
>({ data, xFormat, yFormat, tooltipLabelFormatter, tooltipValueFormatter }: LineProps<D>) {
  const internTooltipLabelFormatter = useRawTooltipLabelFormatter(tooltipLabelFormatter);
  const internTooltipValueFormatter = useRawTooltipValueFormatter(tooltipValueFormatter);

  return (
    <ResponsiveContainer width="100%" height="100%">
      <LineChart data={data}>
        <RLine
          connectNulls
          type="monotone"
          dataKey="y"
          fill="var(--primary)"
          stroke="var(--primary)"
          strokeWidth={2}
          dot={false}
        />
        <XAxis
          name="X"
          domain={['dataMin', 'dataMax']}
          dataKey="x"
          tickFormatter={xFormat}
          style={{ fontWeight: 'bold' }}
        />
        <YAxis domain={['dataMin', 'dataMax']} tickFormatter={yFormat} />
        <Tooltip
          wrapperStyle={{ zIndex: 10 }}
          contentStyle={{ backgroundColor: 'var(--background)' }}
          labelStyle={{ color: 'var(--text-on-light)' }}
          labelFormatter={internTooltipLabelFormatter}
          formatter={internTooltipValueFormatter}
        />
      </LineChart>
    </ResponsiveContainer>
  );
}
Example #8
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 #9
Source File: DailyIncidents.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.incidentsByDay(context);

    return (
        <div id="daily-incidents" style={{ width: '100%', height: 300, paddingTop: '1.2rem', paddingRight: '1.2rem' }}>
            <ResponsiveContainer>
                <ScatterChart data={dataPoints}>
                    <CartesianGrid strokeDasharray="3 3" />
                    <XAxis dataKey="day" name="Day" />
                    <YAxis dataKey="total" name="Total" />
                    <Tooltip content={<FilterZeroTooltip />} />
                    <Scatter name="day" data={dataPoints} fill="#8884d8" />
                </ScatterChart>
            </ResponsiveContainer>
        </div>
    );
}
Example #10
Source File: index.tsx    From vvs-ui with GNU General Public License v3.0 5 votes vote down vote up
Chart = ({ data, setHoverValue, setHoverDate }: LineChartProps) => {
  const { theme } = useTheme()
  if (!data || data.length === 0) {
    return <BarChartLoader />
  }
  return (
    <ResponsiveContainer width="100%" height="100%">
      <BarChart
        data={data}
        margin={{
          top: 5,
          right: 15,
          left: 0,
          bottom: 5,
        }}
        onMouseLeave={() => {
          setHoverDate(undefined)
          setHoverValue(undefined)
        }}
      >
        <XAxis
          dataKey="time"
          axisLine={false}
          tickLine={false}
          tickFormatter={(time) => format(time, 'dd')}
          minTickGap={10}
        />
        <YAxis
          dataKey="value"
          tickCount={6}
          scale="linear"
          axisLine={false}
          tickLine={false}
          color={theme.colors.textSubtle}
          fontSize="12px"
          tickFormatter={(val) => `$${formatAmount(val)}`}
          orientation="right"
          tick={{ dx: 10, fill: theme.colors.textSubtle }}
        />
        <Tooltip
          cursor={{ fill: theme.colors.backgroundDisabled }}
          contentStyle={{ display: 'none' }}
          formatter={(tooltipValue, name, props) => (
            <HoverUpdater payload={props.payload} setHoverValue={setHoverValue} setHoverDate={setHoverDate} />
          )}
        />
        <Bar
          dataKey="value"
          fill={theme.colors.primary}
          shape={(props) => (
            <CustomBar height={props.height} width={props.width} x={props.x} y={props.y} fill={theme.colors.primary} />
          )}
        />
      </BarChart>
    </ResponsiveContainer>
  )
}
Example #11
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 #12
Source File: StakeGraph.tsx    From mStable-apps with GNU Lesser General Public License v3.0 5 votes vote down vote up
StakeGraph: FC = () => {
  const { data: tokenData } = useStakedTokenQuery()
  const weightedTimestamp = tokenData?.stakedToken?.accounts?.[0]?.balance?.weightedTimestamp

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

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

  const formatTime = (time: number): string => {
    const d = new Date(time);
    return `${('0' + (d.getMonth() + 1)).slice(-2)}/${('0' + d.getDate()).slice(-2)} ${('0' + d.getHours()).slice(
      -2,
    )}:${('0' + d.getMinutes()).slice(-2)}`;
  };

  return (
    <IonRow style={{ height: '200px', width: '100%' }}>
      <IonCol style={{ padding: '0px' }}>
        <ResponsiveContainer>
          <BarChart data={aggregations?.logcount?.buckets}>
            <XAxis
              dataKey="key"
              scale="time"
              type="number"
              domain={['dataMin', 'dataMax']}
              tickFormatter={formatTime}
            />
            {!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, 'Count'];
                }}
                labelFormatter={formatTime}
              />
            ) : null}
            <Bar dataKey="doc_count" stroke="#326ce5" fill="#326ce5" />
          </BarChart>
        </ResponsiveContainer>
      </IonCol>
    </IonRow>
  );
}
Example #16
Source File: OrderChart.tsx    From ra-enterprise-demo with MIT License 5 votes vote down vote up
OrderChart: FC<{ orders?: Order[] }> = ({ orders }) => {
    const translate = useTranslate();
    if (!orders) return null;

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

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

  return (
    <Container>
      <ResponsiveContainer width="100%" aspect={1.75}>
        <AreaChart data={data}>
          <defs>
            <linearGradient id="area" x1="0" y1="0" x2="0" y2="1">
              <stop offset="5%" stopColor={Color.blue} stopOpacity={0.5} />
              <stop offset="95%" stopColor={Color.blue} stopOpacity={0} />
            </linearGradient>
          </defs>
          <XAxis
            dataKey="ordering"
            tickFormatter={ordering => (ordering === 0 ? 'Last claim' : 'Now')}
            axisLine={false}
            padding={{ left: 16 }}
            tickLine={false}
          />
          <YAxis tickCount={2} tickFormatter={m => `${m}`} axisLine={false} padding={{ bottom: 16 }} tickLine={false} width={32} />
          <Tooltip
            cursor
            label=""
            labelFormatter={w => (w === 0 ? 'Last claim' : 'Available to claim')}
            formatter={mta => `${(mta as number).toFixed(2)} MTA`}
            separator=""
            contentStyle={{
              fontSize: '14px',
              padding: '8px',
              background: 'rgba(255, 255, 255, 0.8)',
              textAlign: 'right',
              border: 'none',
              borderRadius: '4px',
              color: Color.black,
            }}
            wrapperStyle={{
              top: 0,
              left: 0,
            }}
          />
          <Area type="monotone" name={'Earned: '} dataKey="mta" stroke={Color.blue} strokeWidth={2} fill="url(#area)" />
        </AreaChart>
      </ResponsiveContainer>
    </Container>
  )
}
Example #18
Source File: index.tsx    From glide-frontend with GNU General Public License v3.0 5 votes vote down vote up
Chart = ({ data, setHoverValue, setHoverDate }: LineChartProps) => {
  const { theme } = useTheme()
  if (!data || data.length === 0) {
    return <BarChartLoader />
  }
  return (
    <ResponsiveContainer width="100%" height="100%">
      <BarChart
        data={data}
        margin={{
          top: 5,
          right: 15,
          left: 0,
          bottom: 5,
        }}
        onMouseLeave={() => {
          setHoverDate(undefined)
          setHoverValue(undefined)
        }}
      >
        <XAxis
          dataKey="time"
          axisLine={false}
          tickLine={false}
          tickFormatter={(time) => format(time, 'dd')}
          minTickGap={10}
        />
        <YAxis
          dataKey="value"
          tickCount={6}
          scale="linear"
          axisLine={false}
          tickLine={false}
          color={theme.colors.textSubtle}
          fontSize="12px"
          tickFormatter={(val) => `$${formatAmount(val)}`}
          orientation="right"
          tick={{ dx: 10, fill: theme.colors.textSubtle }}
        />
        <Tooltip
          cursor={{ fill: theme.colors.backgroundDisabled }}
          contentStyle={{ display: 'none' }}
          formatter={(tooltipValue, name, props) => (
            <HoverUpdater payload={props.payload} setHoverValue={setHoverValue} setHoverDate={setHoverDate} />
          )}
        />
        <Bar
          dataKey="value"
          fill={theme.colors.primary}
          shape={(props) => (
            <CustomBar height={props.height} width={props.width} x={props.x} y={props.y} fill={theme.colors.primary} />
          )}
        />
      </BarChart>
    </ResponsiveContainer>
  )
}
Example #19
Source File: index.tsx    From Lux-Viewer-2021 with Apache License 2.0 5 votes vote down vote up
Graph = ({ data, ylabel, xlabel }: GraphProps) => {
  const renderColorfulLegendText = (value: string, entry: any) => {
    const { color } = entry;

    return <span style={{ color: '#f9efe2' }}>{value}</span>;
  };
  return (
    <div className="Graph">
      <ResponsiveContainer width={'100%'} height={220}>
        <LineChart
          // width={200}
          onClick={() => {}}
          // height={150}
          data={data}
          margin={{ top: 15, right: 20, left: 0, bottom: 15 }}
        >
          <CartesianGrid strokeDasharray="3 3" />
          <XAxis dataKey="name">
            <Label
              value={xlabel}
              offset={-15}
              position="insideBottom"
              fill="#f9efe2"
            />
          </XAxis>
          <YAxis
            label={{
              value: ylabel,
              angle: -90,
              position: 'insideLeft',
              fill: '#f9efe2',
              color: 'f9efe2',
            }}
          ></YAxis>
          <Tooltip labelStyle={{ color: '#323D34' }} />
          {/* <Legend
            verticalAlign="top"
            height={36}
            formatter={renderColorfulLegendText}
          /> */}
          <Line
            type="monotone"
            dataKey="team0"
            name="Team 0"
            dot={false}
            strokeWidth={2}
            isAnimationActive={false}
            stroke={TEAM_A_COLOR_STR}
          />
          <Line
            type="monotone"
            dataKey="team1"
            name="Team 1"
            dot={false}
            strokeWidth={2}
            isAnimationActive={false}
            stroke={TEAM_B_COLOR_STR}
          />
        </LineChart>
      </ResponsiveContainer>
    </div>
  );
}
Example #20
Source File: StackedBar.tsx    From your_spotify with GNU General Public License v3.0 5 votes vote down vote up
export default function Bar({
  data,
  xFormat,
  yFormat,
  tooltipLabelFormatter,
  tooltipValueFormatter,
  tooltipItemSorter,
  customXTick,
}: StackedBarProps) {
  const realFormatter = useMemo(() => {
    if (tooltipValueFormatter) {
      return (...args: any[]) => [tooltipValueFormatter(...args), null];
    }
    return undefined;
  }, [tooltipValueFormatter]);

  const allKeys = useMemo(
    () =>
      data.reduce<Set<string>>((acc, curr) => {
        Object.keys(curr)
          .filter((key) => key !== 'x')
          .forEach((key) => acc.add(key));
        return acc;
      }, new Set()),
    [data],
  );

  return (
    <ResponsiveContainer width="100%" height="100%">
      <BarChart data={data}>
        <XAxis
          dataKey="x"
          tickFormatter={xFormat}
          tick={customXTick}
          style={{ fontWeight: 'bold' }}
        />
        <YAxis tickFormatter={yFormat} width={40} />
        {Array.from(allKeys).map((k, index) => (
          <RBar key={k} stackId="only" dataKey={k} fill={getColor(index)} />
        ))}
        <Tooltip
          wrapperStyle={{ zIndex: 10 }}
          contentStyle={{ backgroundColor: 'var(--background)' }}
          labelStyle={{ color: 'var(--text-on-light)' }}
          labelFormatter={tooltipLabelFormatter}
          formatter={realFormatter}
          itemSorter={tooltipItemSorter}
        />
      </BarChart>
    </ResponsiveContainer>
  );
}
Example #21
Source File: SimplePriceChart.tsx    From index-ui with MIT License 4 votes vote down vote up
MarketDataChart: React.FC<SimplePriceChartProps> = ({
  title,
  showTooltip,
  icon,
  data,
  hourlyData,
  onMouseMove = () => {},
  onMouseLeave = () => {},
  setChartRange = () => {},
}) => {
  const theme = useTheme()
  const formatFloats = (n: number) => parseFloat(numeral(n).format('0.00a'))
  const formatToolTip = (chartData: any) => {
    if (!chartData) return ['--', 'No Data Available']
    const {
      payload: { x, y },
    } = chartData
    let timeString = new Date(x).toLocaleDateString()
    if (durationSelector === Durations.DAILY) {
      timeString = new Date(x).toLocaleTimeString([], {
        hour: 'numeric',
        minute: 'numeric',
      })
    }
    return [timeString, '$' + formatFloats(y)]
  }

  const [durationSelector, setDurationSelector] = useState<number>(
    Durations.MONTHLY
  )
  const [price, setPrice] = useState(data)

  useEffect(() => {
    setTimeout(() => {
      const hourlyDataInterval = 24
      if (durationSelector === Durations.DAILY) {
        setPrice(
          hourlyData?.slice(
            -PriceChartRangeOption.DAILY_PRICE_RANGE * hourlyDataInterval
          )
        ) //last day, hourly
      } else if (durationSelector === Durations.WEEKLY) {
        setPrice(
          hourlyData?.slice(
            -PriceChartRangeOption.WEEKLY_PRICE_RANGE * hourlyDataInterval
          )
        ) //last 7 days, hourly
      } else if (durationSelector === Durations.MONTHLY) {
        setPrice(
          hourlyData?.slice(
            -PriceChartRangeOption.MONTHLY_PRICE_RANGE * hourlyDataInterval
          )
        ) //last 30 days, hourly
      } else if (durationSelector === Durations.QUARTERLY) {
        setPrice(
          hourlyData?.slice(
            -PriceChartRangeOption.QUARTERLY_PRICE_RANGE * hourlyDataInterval
          )
        ) //last 90 days, hourly
      } else if (durationSelector === Durations.YEARLY) {
        setPrice(data?.slice(-PriceChartRangeOption.YEARLY_PRICE_RANGE)) //last year, daily
      }
    }, 0)
  }, [durationSelector, data, hourlyData])

  const handleDailyButton = () => {
    setDurationSelector(Durations.DAILY)
    setChartRange(PriceChartRangeOption.DAILY_PRICE_RANGE)
  }

  const handleWeeklyButton = () => {
    setDurationSelector(Durations.WEEKLY)
    setChartRange(PriceChartRangeOption.WEEKLY_PRICE_RANGE)
  }

  const handleMonthlyButton = () => {
    setDurationSelector(Durations.MONTHLY)
    setChartRange(PriceChartRangeOption.MONTHLY_PRICE_RANGE)
  }

  const handleQuarterlyButton = () => {
    setDurationSelector(Durations.QUARTERLY)
    setChartRange(PriceChartRangeOption.QUARTERLY_PRICE_RANGE)
  }

  const handleYearlyButton = () => {
    setDurationSelector(Durations.YEARLY)
    setChartRange(PriceChartRangeOption.YEARLY_PRICE_RANGE)
  }

  const renderTooltip = (props: any) => {
    if (!showTooltip) return null

    const tooltipData = props.payload?.[0]
    const [label, value] = formatToolTip(tooltipData)

    return <FancyValue icon={icon} label={label} value={value} />
  }

  const tickFormatter = (val: any) => {
    if (val <= minY) return 'Min: $' + formatFloats(val)
    return 'Max: $' + formatFloats(val)
  }

  const minY = Math.min(...(price || []).map<number>(({ y }) => y))
  const maxY = Math.max(...(price || []).map<number>(({ y }) => y))
  const minimumYAxisLabel = minY - 5 > 0 ? minY - 5 : 0

  return (
    <Container size='lg'>
      {title && <ChartTitle>{title}</ChartTitle>}
      <ChartContainer>
        <LineChart
          data={price}
          onMouseMove={onMouseMove}
          onMouseLeave={onMouseLeave}
        >
          <Line
            type='monotone'
            dataKey='y'
            dot={false}
            stroke={'url(#gradient)'}
            strokeWidth={2}
            animationEasing='ease'
            animationDuration={800}
          />
          <YAxis
            stroke={theme.colors.grey[500]}
            tickFormatter={tickFormatter}
            axisLine={false}
            tickLine={false}
            mirror={true}
            ticks={[minimumYAxisLabel + 0.001, maxY + 5.001]}
            domain={[minY - 15, maxY + 5]}
            orientation='right'
            width={100}
            dy={7}
            dx={1}
          />
          <Tooltip
            content={renderTooltip}
            wrapperStyle={{ backgroundColor: theme.baseColor }}
            cursor={{ stroke: theme.colors.primary.light, strokeWidth: 2 }}
          />
          <defs>
            <linearGradient id='gradient' gradientTransform='rotate(90)'>
              <stop offset='5%' stopColor='#8150E6' />
              <stop offset='95%' stopColor='#E825A3' />
            </linearGradient>
          </defs>
        </LineChart>
      </ChartContainer>
      <DurationWrapper>
        <ButtonWrapper data-cy='date-range-selector'>
          <Button
            full
            size={'sm'}
            text='1D'
            variant={
              durationSelector === Durations.DAILY ? 'default' : 'secondary'
            }
            onClick={handleDailyButton}
          />
          <Spacer size={'sm'} />
          <Button
            full
            size={'sm'}
            text='1W'
            variant={
              durationSelector === Durations.WEEKLY ? 'default' : 'secondary'
            }
            onClick={handleWeeklyButton}
          />
          <Spacer size={'sm'} />
          <Button
            full
            size={'sm'}
            text='1M'
            variant={
              durationSelector === Durations.MONTHLY ? 'default' : 'secondary'
            }
            onClick={handleMonthlyButton}
          />
          <Spacer size={'sm'} />
          <Button
            full
            size={'sm'}
            text='3M'
            variant={
              durationSelector === Durations.QUARTERLY ? 'default' : 'secondary'
            }
            onClick={handleQuarterlyButton}
          />
          <Spacer size={'sm'} />
          <Button
            full
            size={'sm'}
            text='1Y'
            variant={
              durationSelector === Durations.YEARLY ? 'default' : 'secondary'
            }
            onClick={handleYearlyButton}
          />
        </ButtonWrapper>
      </DurationWrapper>
    </Container>
  )
}
Example #22
Source File: Profile.tsx    From avalon.ist with MIT License 4 votes vote down vote up
render() {
    const { initialHeight } = this;
    const {
      myname,
      style: { themeLight },
    } = this.props.match.params;

    const theme = themeLight ? 'light' : 'dark';
    const data: any[] = [];

    // const { avatarStyle } = this.props.match.params.style;
    const {
      username,
      nationality,
      bio,
      gameRating,
      gameHistory,
      games,
      gameStats,
      gameShots,
      avatars,
      showSpy,
      redirect,
    } = this.state;

    for (const k in gameStats) {
      const stat = gameStats[k];

      data.push({
        name: k.charAt(0).toUpperCase() + k.slice(1),
        wins: stat[0],
        total: stat[1],
        Winrate: stat[1] === 0 ? 0 : Percent(stat[0] / stat[1]),
        color: SPY_ROLES.has(k) ? '#ff6384' : '#36a2eb',
      });
    }

    const country = countries.find((c) => c.text === nationality);
    const totalWon = games[0];
    const totalLost = games[1] - totalWon;
    const winRate = games[1] > 0 ? Percent(totalWon / games[1]) : 0;
    const shotRate = gameShots[1] > 0 ? Percent(gameShots[0] / gameShots[1]) : 0;

    let countryFlag = <img alt={'UN'} src={UN_FLAG} />;
    if (country && country.value != 'UN') {
      if (country.value == 'LGBT') {
        countryFlag = <img alt={'Stonewall'} src={STONEWALL_FLAG} />;
      } else {
        countryFlag = <Flag code={country.value} />;
      }
    }

    return redirect ? (
      <Redirect to="/profile-not-found" />
    ) : (
      <div id="Background-2" className={`full ${theme}`}>
        <Navbar username="" key={'Navbar'} />
        <AvalonScrollbars>
          <div id="Profile" style={{ minHeight: `${initialHeight}px` }}>
            <div className="row">
              <div id="user">
                <img
                  src={showSpy ? avatars.spy : avatars.res}
                  alt={'Avatar'}
                  onMouseOver={this.onHover}
                  onMouseLeave={this.onStopHover}
                />
                <div className="user-tag">
                  {countryFlag}
                  <p>
                    <b>{username}</b>
                    <br />
                    {nationality}
                  </p>
                </div>
              </div>
              <div id="bio" className="bubble">
                <AvalonScrollbars>
                  <ReactMarkdown
                    className="markdown"
                    allowedTypes={[
                      'text',
                      'paragraph',
                      'emphasis',
                      'strong',
                      'thematicBreak',
                      'blockquote',
                      'list',
                      'listItem',
                      'heading',
                    ]}
                  >
                    {bio}
                  </ReactMarkdown>
                </AvalonScrollbars>
              </div>
            </div>
            <div className="row">
              <div id="stats">
                <h1>STATISTICS</h1>
                <table>
                  <tbody>
                    <tr>
                      <th>Statistic</th>
                      <th>Value</th>
                    </tr>
                    <tr>
                      <td>Total Games Played</td>
                      <td>{games[1]}</td>
                    </tr>
                    <tr>
                      <td>Total Games Won</td>
                      <td>{totalWon}</td>
                    </tr>
                    <tr>
                      <td>Total Games Lost</td>
                      <td>{totalLost}</td>
                    </tr>
                    <tr>
                      <td>Total Win Rate</td>
                      <td>{winRate}%</td>
                    </tr>
                    <tr>
                      <td>Shot Accuracy</td>
                      <td>{shotRate}%</td>
                    </tr>
                    <tr>
                      <td>Rating</td>
                      <td>{gameRating}</td>
                    </tr>
                  </tbody>
                </table>
              </div>
              <div id="graph">
                <ResponsiveContainer width={'100%'} height={300}>
                  <BarChart
                    layout="vertical"
                    margin={{
                      top: 20,
                      right: 20,
                      bottom: 20,
                      left: 20,
                    }}
                    data={data}
                  >
                    <CartesianGrid strokeDasharray="1 1" />
                    <XAxis type="number" domain={[0, 100]} />
                    <YAxis type="category" width={100} dataKey="name" />
                    <Tooltip content={<CustomTooltip />} />
                    <Bar dataKey="Winrate" fill="#8884d8">
                      {data.map((entry, index) => (
                        <Cell key={`cell-${index}`} fill={entry.color} />
                      ))}
                    </Bar>
                  </BarChart>
                </ResponsiveContainer>
              </div>
            </div>
            <div className="row">
              <div id="history">
                <h1>GAME HISTORY</h1>
                <table>
                  <tbody>
                    <tr>
                      <th>Game</th>
                      <th>Role</th>
                      <th>Size</th>
                      <th>Winner</th>
                      <th>Date</th>
                    </tr>
                    {gameHistory
                      .slice(-10)
                      .reverse()
                      .map((g: any, i) => {
                        const date = new Date(g.date);
                        const month = ('00' + (date.getUTCMonth() + 1)).slice(-2);
                        const day = ('00' + date.getUTCDate()).slice(-2);
                        const year = date.getUTCFullYear();

                        return (
                          <tr key={'Game' + g.id}>
                            <td>
                              <Link to={'/game/' + g.id}>#{g.code}</Link>
                            </td>
                            <td>{g.role}</td>
                            <td>{g.size}</td>
                            <td>{g.winner ? 'Resistance' : 'Spy'}</td>
                            <td>
                              {year}-{month}-{day}
                            </td>
                          </tr>
                        );
                      })}
                  </tbody>
                </table>
              </div>
            </div>
          </div>
        </AvalonScrollbars>
        {myname === username ? (
          <button
            className="button-b edit-your-profile-with-this"
            type="button"
            onClick={this.onFormToggle}
          >
            <p>Edit Profile</p>
          </button>
        ) : null}
        {this.state.showForm ? (
          <EditProfile
            onExit={this.onFormToggle}
            text="Submit"
            nationality={nationality}
            bio={bio}
            title="EDIT YOUR PROFILE"
            onSelect={this.onEdit}
          />
        ) : null}
      </div>
    );
  }
Example #23
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 #24
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 #25
Source File: LiquidityChart.tsx    From mStable-apps with GNU Lesser General Public License v3.0 4 votes vote down vote up
Chart: FC<{
  aggregateMetrics: {
    type: string
    enabled: boolean
    label: string
    color: string
  }[]
}> = ({ aggregateMetrics }) => {
  const poolAddress = useSelectedFeederPoolAddress()
  const data = useTotalLiquidity(poolAddress)
  const dateFilter = useDateFilter()
  const { metrics } = useMetricsState()
  return (
    <RechartsContainer>
      {data.length < 2 && <NoData>No data yet</NoData>}
      <ResponsiveContainer aspect={2} debounce={1} width="99%">
        <AreaChart margin={{ top: 40, right: 0, bottom: 0, left: 0 }} barCategoryGap={1} data={data.length > 1 ? data : []}>
          <defs>
            {aggregateMetrics.map(({ type, color }) => (
              <linearGradient id={type} key={type} x1="0" y1="0" x2="0" y2="1">
                <stop offset="5%" stopColor={color} stopOpacity={0.5} />
                <stop offset="95%" stopColor={color} stopOpacity={0} />
              </linearGradient>
            ))}
          </defs>
          <XAxis
            dataKey="timestamp"
            axisLine={false}
            xAxisId={0}
            height={0}
            tick={false}
            tickFormatter={timestamp => (timestamp ? format(timestamp * 1000, periodFormatMapping[dateFilter.period]) : '')}
          />
          <YAxis
            type="number"
            orientation="left"
            tickFormatter={toK}
            axisLine={false}
            interval="preserveEnd"
            yAxisId={0}
            tick={false}
            width={0}
          />
          <Tooltip
            cursor
            labelFormatter={timestamp => format((timestamp as number) * 1000, 'yyyy-MM-dd HH:mm')}
            formatter={toK as never}
            separator=""
            contentStyle={{
              fontSize: '14px',
              padding: '8px',
              background: 'rgba(255, 255, 255, 0.8)',
              textAlign: 'right',
              border: 'none',
              borderRadius: '4px',
              color: Color.black,
            }}
            wrapperStyle={{
              top: 0,
              left: 0,
            }}
          />
          {metrics.map(({ color, type, label, enabled }) => (
            <Area
              animationDuration={100}
              key={type}
              type="monotone"
              hide={!enabled}
              dataKey={type}
              name={`${label} `}
              opacity={1}
              dot={false}
              yAxisId={0}
              stroke={color}
              strokeWidth={2}
              fill={`url(#${type})`}
            />
          ))}
        </AreaChart>
      </ResponsiveContainer>
    </RechartsContainer>
  )
}
Example #26
Source File: Balances.tsx    From abrechnung with GNU Affero General Public License v3.0 4 votes vote down vote up
export default function Balances({ group }) {
    const theme: Theme = useTheme();
    const isSmallScreen = useMediaQuery(theme.breakpoints.down("sm"));
    const history = useHistory();

    const personalAccounts = useRecoilValue(personalAccountsSeenByUser(group.id));
    const clearingAccounts = useRecoilValue(clearingAccountsSeenByUser(group.id));
    const balances = useRecoilValue(accountBalances(group.id));

    const [selectedTab, setSelectedTab] = useState("1");

    const colorGreen = theme.palette.mode === "light" ? theme.palette.success.light : theme.palette.success.dark;
    const colorRed = theme.palette.mode === "light" ? theme.palette.error.light : theme.palette.error.dark;
    const colorGreenInverted = theme.palette.mode === "dark" ? theme.palette.success.light : theme.palette.success.dark;
    const colorRedInverted = theme.palette.mode === "dark" ? theme.palette.error.light : theme.palette.error.dark;

    useTitle(`${group.name} - Balances`);

    const chartData = personalAccounts.map((account) => {
        return {
            name: account.name,
            balance: balances[account.id].balance,
            totalPaid: balances[account.id].totalPaid,
            totalConsumed: balances[account.id].totalConsumed,
            id: account.id,
        };
    });

    const unbalancedClearingAccounts = clearingAccounts
        .filter((account) => balances[account.id].balance !== 0)
        .map((account) => {
            return {
                name: account.name,
                id: account.id,
                balance: balances[account.id].balance,
            };
        });

    const chartHeight = Object.keys(balances).length * 30 + 100;

    // TODO determine the rendered width of the account names and take the maximum
    const yaxiswidth = isSmallScreen
        ? Math.max(Math.max(...personalAccounts.map((account) => account.name.length)), 20)
        : Math.max(...personalAccounts.map((account) => account.name.length)) * 7 + 5;

    const handleBarClick = (data, event) => {
        const id = data.activePayload[0].payload.id;
        history.push(`/groups/${group.id}/accounts/${id}`);
    };

    return (
        <MobilePaper>
            <TabContext value={selectedTab}>
                <Box sx={{ borderBottom: 1, borderColor: "divider" }}>
                    <TabList onChange={(event, idx) => setSelectedTab(idx)} centered>
                        <Tab label="Chart" value="1" />
                        <Tab label="Table" value="2" />
                    </TabList>
                </Box>
                <TabPanel value="1" sx={{ padding: { xs: 1, md: 2 } }}>
                    {personalAccounts.length === 0 && <Alert severity="info">No Accounts</Alert>}
                    {unbalancedClearingAccounts.length !== 0 && (
                        <Alert severity="info">
                            <AlertTitle>Some Clearing Accounts have remaining balances.</AlertTitle>
                            {unbalancedClearingAccounts.map((account) => (
                                <Typography variant="body2" key={account.id} component="span">
                                    <>{account.name}:</>
                                    <Typography
                                        variant="body2"
                                        component="span"
                                        sx={{ color: account.balance < 0 ? colorRedInverted : colorGreenInverted }}
                                    >
                                        {account.balance.toFixed(2)} {group.currency_symbol}{" "}
                                    </Typography>
                                </Typography>
                            ))}
                        </Alert>
                    )}
                    {isSmallScreen ? (
                        <List>
                            {personalAccounts.map((account) => (
                                <>
                                    <ListItemLink key={account.id} to={`/groups/${group.id}/accounts/${account.id}`}>
                                        <ListItemText primary={account.name} />
                                        <Typography
                                            align="right"
                                            variant="body2"
                                            sx={{
                                                color:
                                                    balances[account.id].balance < 0
                                                        ? colorRedInverted
                                                        : colorGreenInverted,
                                            }}
                                        >
                                            {balances[account.id].balance.toFixed(2)} {group.currency_symbol}
                                        </Typography>
                                    </ListItemLink>
                                    <Divider key={account.id * 2} component="li" />
                                </>
                            ))}
                        </List>
                    ) : (
                        <div className="area-chart-wrapper" style={{ width: "100%", height: `${chartHeight}px` }}>
                            <ResponsiveContainer>
                                <BarChart
                                    data={chartData}
                                    margin={{
                                        top: 20,
                                        right: 20,
                                        bottom: 20,
                                        left: 20,
                                    }}
                                    layout="vertical"
                                    onClick={handleBarClick}
                                >
                                    <XAxis
                                        stroke={theme.palette.text.primary}
                                        type="number"
                                        unit={group.currency_symbol}
                                    />
                                    <YAxis
                                        dataKey="name"
                                        stroke={theme.palette.text.primary}
                                        type="category"
                                        width={yaxiswidth}
                                    />
                                    <Tooltip
                                        formatter={(label) =>
                                            parseFloat(label).toFixed(2) + ` ${group.currency_symbol}`
                                        }
                                        labelStyle={{
                                            color: theme.palette.text.primary,
                                        }}
                                        itemStyle={{
                                            color: theme.palette.text.primary,
                                        }}
                                        contentStyle={{
                                            backgroundColor: theme.palette.background.paper,
                                            borderColor: theme.palette.divider,
                                            borderRadius: theme.shape.borderRadius,
                                        }}
                                    />
                                    <Bar dataKey="balance">
                                        {chartData.map((entry, index) => {
                                            return (
                                                <Cell
                                                    key={`cell-${index}`}
                                                    fill={entry["balance"] >= 0 ? colorGreen : colorRed}
                                                />
                                            );
                                        })}
                                        <LabelList
                                            dataKey={(entry) =>
                                                `${entry["balance"].toFixed(2)}${group.currency_symbol}`
                                            }
                                            position="insideLeft"
                                            fill={theme.palette.text.primary}
                                        />
                                    </Bar>
                                </BarChart>
                            </ResponsiveContainer>
                        </div>
                    )}
                </TabPanel>
                <TabPanel value="2" sx={{ padding: { xs: 1, md: 2 } }}>
                    <BalanceTable group={group} />
                </TabPanel>
            </TabContext>
        </MobilePaper>
    );
}
Example #27
Source File: ArtistListeningRepartition.tsx    From your_spotify with GNU General Public License v3.0 4 votes vote down vote up
export default function ArtistListeningRepartition({ className }: ArtistListeningRepartitionProps) {
  const { interval } = useSelector(selectRawIntervalDetail);
  const results = useAPI(api.mostListenedArtist, interval.start, interval.end, interval.timesplit);

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

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

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

  const tooltipLabelFormatter = useRawTooltipLabelFormatter(formatXAxisDateTooltip, false);

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

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

  const formatX = useFormatXAxis(data);

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

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

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

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

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

        stepCalc = periods < 1 ? 15 : periods;
      }

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

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

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

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

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

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

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

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

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

                        <stop
                          offset="95%"
                          stopColor="#ffffff"
                          stopOpacity={0.8}
                        />
                      </linearGradient>
                    </defs>
                  )}
                  <CartesianGrid
                    strokeDasharray={areaWidget ? "2 2" : "5 5"}
                    strokeWidth={1}
                    strokeOpacity={1}
                    stroke={"#eee0e0"}
                    vertical={!areaWidget}
                  />
                  <XAxis
                    dataKey="name"
                    tickFormatter={(value: any) => xAxisFormatter(value)}
                    interval={intervalCount}
                    tick={{
                      fontSize: "68%",
                      fontWeight: "normal",
                      color: "#404143",
                    }}
                    tickCount={10}
                    stroke={"#082045"}
                  />
                  <YAxis
                    type={"number"}
                    domain={[0, dataMax * 1.1]}
                    hide={hideYAxis}
                    tickFormatter={(value: any) => yAxisFormatter(value)}
                    tick={{
                      fontSize: "68%",
                      fontWeight: "normal",
                      color: "#404143",
                    }}
                    stroke={"#082045"}
                  />
                  {linearConfiguration.map((section, index) => {
                    return (
                      <Area
                        key={`area-${section.dataKey}-${index.toString()}`}
                        type="monotone"
                        dataKey={section.dataKey}
                        isAnimationActive={false}
                        stroke={!areaWidget ? section.lineColor : "#D7E5F8"}
                        fill={areaWidget ? "url(#colorUv)" : section.fillColor}
                        fillOpacity={areaWidget ? 0.65 : 0}
                        strokeWidth={!areaWidget ? 3 : 0}
                        strokeLinecap={"round"}
                        dot={areaWidget ? <CustomizedDot /> : false}
                      />
                    );
                  })}
                  <Tooltip
                    content={
                      <LineChartTooltip
                        linearConfiguration={linearConfiguration}
                        yAxisFormatter={yAxisFormatter}
                      />
                    }
                    wrapperStyle={{
                      zIndex: 5000,
                    }}
                  />
                </AreaChart>
              </ResponsiveContainer>
            </div>
            {!areaWidget && (
              <Fragment>
                {zoomActivated && (
                  <Fragment>
                    <strong>Series</strong>
                    <br />
                    <br />
                  </Fragment>
                )}
                {biggerThanMd && (
                  <div className={classes.legendChart}>
                    {linearConfiguration.map((section, index) => {
                      return (
                        <div
                          className={classes.singleLegendContainer}
                          key={`legend-${section.keyLabel}-${index.toString()}`}
                        >
                          <div
                            className={classes.colorContainer}
                            style={{ backgroundColor: section.lineColor }}
                          />
                          <div className={classes.legendLabel}>
                            {section.keyLabel}
                          </div>
                        </div>
                      );
                    })}
                  </div>
                )}
              </Fragment>
            )}
          </React.Fragment>
        )}
      </Box>
    </Box>
  );
}
Example #29
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>
  );
}