recharts#Legend TypeScript Examples
The following examples show how to use
recharts#Legend.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: PeriodByResponderGraph.tsx From backstage-plugin-opsgenie with MIT License | 6 votes |
PeriodByResponderGraph = ({data}: {data: IncidentsByResponders}) => {
return (
<ResponsiveContainer>
<ComposedChart data={data.dataPoints}>
<CartesianGrid strokeDasharray="3 3" />
<XAxis dataKey="period" />
<YAxis />
{data.responders.map(responder => (
<Bar dataKey={responder} fill={colorForString(responder)} stackId="a" barSize={30} key={responder} />
))}
<Line type="monotone" dataKey="total" name="Total" stroke="#ff7300" />
<Tooltip content={<FilterZeroTooltip />} />
<Legend />
</ComposedChart>
</ResponsiveContainer>
);
}
Example #2
Source File: Debug.tsx From watchparty with MIT License | 6 votes |
Debug = () => {
const [data, setData] = useState([]);
// eslint-disable-next-line
useEffect(
(async () => {
const response = await fetch(timeSeriesUrl);
const json = await response.json();
json.reverse();
setData(json);
}) as any,
[setData]
);
const keys = Object.keys(data.slice(-1)[0] ?? {});
return (
<>
{keys.map((key) => (
<LineChart
width={1400}
height={400}
data={data}
margin={{
top: 5,
left: 20,
bottom: 5,
}}
>
<CartesianGrid />
<XAxis dataKey="time" />
<YAxis />
<Tooltip />
<Legend />
<Line type="monotone" dataKey={key} stroke="#8884d8" />
</LineChart>
))}
</>
);
}
Example #3
Source File: QueueSizeChart.tsx From asynqmon with MIT License | 6 votes |
function QueueSizeChart(props: Props) {
const theme = useTheme();
const handleClick = (params: { activeLabel?: string } | null) => {
const allQueues = props.data.map((b) => b.queue);
if (
params &&
params.activeLabel &&
allQueues.includes(params.activeLabel)
) {
history.push(queueDetailsPath(params.activeLabel));
}
};
const history = useHistory();
return (
<ResponsiveContainer>
<BarChart
data={props.data}
maxBarSize={120}
onClick={handleClick}
style={{ cursor: "pointer" }}
>
<CartesianGrid strokeDasharray="3 3" />
<XAxis dataKey="queue" stroke={theme.palette.text.secondary} />
<YAxis stroke={theme.palette.text.secondary} />
<Tooltip />
<Legend />
<Bar dataKey="active" stackId="a" fill="#1967d2" />
<Bar dataKey="pending" stackId="a" fill="#669df6" />
<Bar dataKey="aggregating" stackId="a" fill="#e69138" />
<Bar dataKey="scheduled" stackId="a" fill="#fdd663" />
<Bar dataKey="retry" stackId="a" fill="#f666a9" />
<Bar dataKey="archived" stackId="a" fill="#ac4776" />
<Bar dataKey="completed" stackId="a" fill="#4bb543" />
</BarChart>
</ResponsiveContainer>
);
}
Example #4
Source File: ProcessedTasksChart.tsx From asynqmon with MIT License | 6 votes |
function ProcessedTasksChart(props: Props) {
const theme = useTheme<Theme>();
return (
<ResponsiveContainer>
<BarChart data={props.data} maxBarSize={120}>
<CartesianGrid strokeDasharray="3 3" />
<XAxis dataKey="queue" stroke={theme.palette.text.secondary} />
<YAxis stroke={theme.palette.text.secondary} />
<Tooltip />
<Legend />
<Bar
dataKey="succeeded"
stackId="a"
fill={theme.palette.success.light}
/>
<Bar dataKey="failed" stackId="a" fill={theme.palette.error.light} />
</BarChart>
</ResponsiveContainer>
);
}
Example #5
Source File: DailyStatsChart.tsx From asynqmon with MIT License | 6 votes |
export default function DailyStatsChart(props: Props) {
const data = makeChartData(props.data, props.numDays);
const theme = useTheme<Theme>();
return (
<ResponsiveContainer>
<LineChart data={data}>
<CartesianGrid strokeDasharray="3 3" />
<XAxis
dataKey="date"
minTickGap={10}
stroke={theme.palette.text.secondary}
/>
<YAxis stroke={theme.palette.text.secondary} />
<Tooltip />
<Legend />
<Line
type="monotone"
dataKey="succeeded"
stroke={theme.palette.success.main}
/>
<Line
type="monotone"
dataKey="failed"
stroke={theme.palette.error.main}
/>
</LineChart>
</ResponsiveContainer>
);
}
Example #6
Source File: ChartCard.tsx From genshin-optimizer with MIT License | 6 votes |
function Chart({ displayData, plotNode, valueNode, showMin }: {
displayData: Point[],
plotNode: NumNode,
valueNode: NumNode,
showMin: boolean
}) {
const plotBaseUnit = KeyMap.unit(plotNode.info?.key)
const valueUnit = KeyMap.unit(valueNode.info?.key)
return <ResponsiveContainer width="100%" height={600}>
<ComposedChart data={displayData}>
<CartesianGrid strokeDasharray="3 3" />
<XAxis dataKey="x" scale="linear" unit={plotBaseUnit} domain={["auto", "auto"]} tick={{ fill: 'white' }} type="number" tickFormatter={n => n > 10000 ? n.toFixed() : n.toFixed(1)} />
<YAxis name="DMG" domain={["auto", "auto"]} unit={valueUnit} allowDecimals={false} tick={{ fill: 'white' }} type="number" />
<ZAxis dataKey="y" range={[3, 25]} />
<Legend />
<Scatter name="Optimization Target" dataKey="y" fill="#8884d8" line lineType="fitting" isAnimationActive={false} />
{showMin && <Line name="Minimum Stat Requirement Threshold" dataKey="min" stroke="#ff7300" type="stepBefore" connectNulls strokeWidth={2} isAnimationActive={false} />}
</ComposedChart>
</ResponsiveContainer>
}
Example #7
Source File: ScatterChart.tsx From opensaas with MIT License | 6 votes |
ScatterChart: React.FC<ScatterChartProps> = (props: ScatterChartProps) => {
const { data, width, height, showGrid, strokeColor, fillColor, scatterName } = props;
return (
<ResponsiveContainer>
<RechartsScatterChart width={width} height={height}>
{showGrid ? <CartesianGrid strokeDasharray='3 3' /> : null}
<XAxis type='number' dataKey='x' name={data?.xname} tickLine={false} />
<YAxis type='number' dataKey='y' name={data?.yname} tickLine={false} />
<Tooltip />
<Legend
verticalAlign='top'
content={<CustomizedLegend strokeColor={strokeColor} fillColor={fillColor} scatterName={scatterName} />}
/>
<Scatter
name={scatterName}
data={data.lineChartData}
shape={<CustomizedDot strokeColor={strokeColor} fillColor={fillColor} r={6} cx={10} cy={10} />}
/>
</RechartsScatterChart>
</ResponsiveContainer>
);
}
Example #8
Source File: PieChart.tsx From opensaas with MIT License | 6 votes |
PieChart: React.FC<PieChartProps> = (props: PieChartProps) => {
const { width, height, data = [], colors, pie } = props;
return (
<RechartsPieChart width={width} height={height}>
<Tooltip />
<Legend />
<Pie
data={data}
cx={pie?.cx}
cy={pie?.cy}
innerRadius={pie?.innerRadius}
outerRadius={pie?.outerRadius}
fill='#8884d8'
paddingAngle={pie?.paddingAngle}
dataKey='value'>
{data.map((_entry, index) => (
<Cell key={`cell-${index}`} fill={colors[index % colors.length]} />
))}
</Pie>
</RechartsPieChart>
);
}
Example #9
Source File: LineChart.tsx From opensaas with MIT License | 6 votes |
LineChart: React.FC<LineChartProps> = (props) => {
const { width, height, data, xAxis, line, showGrid, colors } = props;
return (
<ResponsiveContainer>
<RechartsLineChart width={width} height={height}>
{showGrid ? <CartesianGrid strokeDasharray='3 3' /> : null}
<XAxis dataKey='category' type={xAxis.type} allowDuplicatedCategory={false} axisLine={false} tickLine={false} />
<YAxis dataKey='value' axisLine={false} tickLine={false} />
<Tooltip />
<Legend verticalAlign='top' />
{data.map(({ data, name }, index: number) => (
<Line
strokeWidth={line.strokeWidth}
legendType='circle'
type={line.type}
stroke={colors[index % colors.length]}
dataKey='value'
data={data}
name={name}
key={name}
activeDot={line.activeDot}
/>
))}
</RechartsLineChart>
</ResponsiveContainer>
);
}
Example #10
Source File: BarChart.tsx From opensaas with MIT License | 6 votes |
BarChart: React.FC<BarChartProps> = (props) => {
const { width, height, data, barSize, barCategoryGap, showGrid, showLegend, colors } = props;
return (
<ResponsiveContainer>
<RechartsBarChart
width={width}
height={height}
data={data}
barSize={barSize}
barCategoryGap={barCategoryGap}
margin={{
top: 5,
right: 30,
left: 10,
bottom: 5,
}}>
{showGrid ? <CartesianGrid strokeDasharray='3 3' /> : null}
<XAxis dataKey='name' axisLine={false} tickLine={false} />
<YAxis axisLine={false} tickLine={false} />
<Tooltip cursor={false} />
{showLegend ? <Legend /> : null}
{Object.keys(data[0]).map((key: string, index: number) => {
return key !== 'name' ? <Bar dataKey={key} key={key} fill={colors[(index - 1) % colors.length]} /> : null;
})}
</RechartsBarChart>
</ResponsiveContainer>
);
}
Example #11
Source File: TrafficChart.tsx From web-show with Apache License 2.0 | 6 votes |
TrafficChart: React.FC<IProps> = props => {
const { data } = props;
return (
<ResponsiveContainer>
<ComposedChart
barGap="2%"
width={600}
height={400}
margin={{
top: 10,
right: 30,
left: 20,
bottom: 20
}}
data={data}
>
<CartesianGrid strokeDasharray="3 3" />
<XAxis
tickLine={false}
dataKey="time"
domain = {['auto', 'auto']}
tickFormatter = {(unixTime) => moment(unixTime).format('HH:mm:ss Do')}
type = 'number'
/>
<YAxis label={{ value: 'Latency', position: 'insideLeft', angle: -90 }} unit={"ms"}/>
<Tooltip labelFormatter={t => new Date(t).toLocaleString()} />
<Legend />
<Line type="monotone" dataKey="latency" stroke="#8884d8" />
</ComposedChart>
</ResponsiveContainer>
);
}
Example #12
Source File: BuildTimeline.tsx From backstage with Apache License 2.0 | 6 votes |
BuildTimeline = ({
targets,
height,
width,
}: BuildTimelineProps) => {
const theme = useTheme();
if (!targets.length) return <p>No Targets</p>;
const data = getTimelineData(targets);
return (
<ResponsiveContainer
height={height}
width={width}
minHeight={EMPTY_HEIGHT + targets.length * 5}
>
<BarChart layout="vertical" data={data} maxBarSize={10} barGap={0}>
<CartesianGrid strokeDasharray="2 2" />
<XAxis type="number" domain={[0, 'dataMax']} />
<YAxis type="category" dataKey="name" padding={{ top: 0, bottom: 0 }} />
<Tooltip content={<TargetToolTip />} />
<Legend />
<Bar
dataKey="buildTime"
fill={theme.palette.grey[400]}
minPointSize={1}
/>
<Bar dataKey="compileTime" fill={theme.palette.primary.main} />
</BarChart>
</ResponsiveContainer>
);
}
Example #13
Source File: WeeklyIncidentsSeverity.tsx From backstage-plugin-opsgenie with MIT License | 6 votes |
Graph = ({context}: {context: Context}) => {
const analyticsApi = useApi(analyticsApiRef);
const dataPoints = analyticsApi.incidentsByWeekAndSeverity(context);
return (
<div id="weekly-incidents-severity" style={{ width: '100%', height: 300, paddingTop: '1.2rem', paddingRight: '1.2rem' }}>
<ResponsiveContainer>
<ComposedChart data={dataPoints}>
<CartesianGrid strokeDasharray="3 3" />
<XAxis dataKey="week" />
<YAxis />
<Bar dataKey="p1" fill="#bf2600" name="P1 - Critical" stackId="a" barSize={30} />
<Bar dataKey="p2" fill="#ff7452" name="P2 - High" stackId="a" barSize={30} />
<Bar dataKey="p3" fill="#ffab00" name="P3 - Moderate" stackId="a" barSize={30} />
<Bar dataKey="p4" fill="#36b37e" name="P4 - Low" stackId="a" barSize={30} />
<Bar dataKey="p5" fill="#00857A" name="P5 - Informational" stackId="a" barSize={30} />
<Tooltip content={<FilterZeroTooltip />} />
<Legend />
</ComposedChart>
</ResponsiveContainer>
</div>
);
}
Example #14
Source File: WeeklyIncidents.tsx From backstage-plugin-opsgenie with MIT License | 6 votes |
Graph = ({context}: {context: Context}) => {
const analyticsApi = useApi(analyticsApiRef);
const dataPoints = analyticsApi.incidentsByWeekAndHours(context);
return (
<div id="weekly-incidents" style={{ width: '100%', height: 300, paddingTop: '1.2rem', paddingRight: '1.2rem' }}>
<ResponsiveContainer>
<ComposedChart
data={dataPoints}
>
<CartesianGrid strokeDasharray="3 3" />
<XAxis dataKey="week" />
<YAxis />
<Bar dataKey="businessHours" fill="#82ca9d" name="Business hours" stackId="a" barSize={30} />
<Bar dataKey="onCallHours" fill="#8884d8" name="On-call hours" stackId="a" barSize={30} />
<Line type="monotone" dataKey="total" name="Total" stroke="#ff7300" />
<Tooltip content={<FilterZeroTooltip />} />
<Legend />
</ComposedChart>
</ResponsiveContainer>
</div>
);
}
Example #15
Source File: WeeklyImpactResponder.tsx From backstage-plugin-opsgenie with MIT License | 6 votes |
WeeklyImpactResponders = ({ context }: { context: Context }) => {
const graphId = "weekly-impact-responders";
const analyticsApi = useApi(analyticsApiRef);
const data = analyticsApi.impactByWeekAndResponder(context);
return (
<InfoCard title="Average impact by week and responder" action={<SaveAction targetRef={graphId} />}>
<div id={graphId} style={{ width: '100%', height: 450, paddingTop: '1.2rem', paddingRight: '1.2rem' }}>
<ResponsiveContainer>
<ComposedChart data={data.dataPoints}>
<CartesianGrid strokeDasharray="3 3" />
<XAxis dataKey="period" />
<YAxis tickFormatter={value => value === 0 ? '0 min' : moment.duration(value, 'minutes').humanize()} />
{data.responders.map(responder => (
<Bar dataKey={responder} fill={colorForString(responder)} stackId="a" barSize={30} key={responder} />
))}
<Tooltip
formatter={(value: number, name: string) => [value === 0 ? '0 min' : moment.duration(value, 'minutes').humanize(), name]}
content={<FilterZeroTooltip />}
/>
<Legend />
</ComposedChart>
</ResponsiveContainer>
</div>
</InfoCard>
);
}
Example #16
Source File: index.tsx From Demae with MIT License | 6 votes |
OrderChart = () => {
return (
<LineChart
width={500}
height={300}
data={data}
margin={{
top: 5, right: 30, left: 20, bottom: 5,
}}
>
<CartesianGrid strokeDasharray="3 3" />
<XAxis dataKey="name" />
<YAxis />
<Tooltip />
<Legend />
<Line type="monotone" dataKey="pv" stroke="#8884d8" activeDot={{ r: 8 }} />
<Line type="monotone" dataKey="uv" stroke="#82ca9d" />
</LineChart>
);
}
Example #17
Source File: stats.tsx From config-generator with MIT License | 5 votes |
public render() {
const { stats, onRefresh, range } = this.props;
const { strokeWidth } = this.state;
return (
<ResponsiveContainer width="100%" maxHeight={500} aspect={4.0 / 3.0}>
<LineChart
data={stats}
margin={{
top: 25,
right: 30,
left: 20,
bottom: 100,
}}
>
<CartesianGrid strokeDasharray="1 4" />
<XAxis
dataKey="timeStamp"
tick={this.renderCustomAxisTick}
interval={0}
ticks={stats.map((s: any) => s.timeStamp)}
type="number"
domain={['dataMin', 'dataMax']}
/>
<YAxis />
<Tooltip
itemStyle={{ textTransform: 'capitalize' }}
labelFormatter={value =>
range === 'day'
? moment(value).format('DD/MM/YYYY HH:mm:ss')
: moment(value).format('DD/MM/YYYY')
}
labelStyle={{ fontWeight: 'bold', marginBottom: '10px' }}
/>
<Legend
verticalAlign="top"
iconType="circle"
formatter={(value, entry, index) => value.toUpperCase()}
onMouseEnter={this.handleMouseEnter}
onMouseLeave={this.handleMouseLeave}
/>
<Line
type="monotone"
dataKey="all"
connectNulls={true}
stroke="#4F4F4F"
activeDot={{ r: 8 }}
strokeWidth={strokeWidth.all}
/>
<Line
type="monotone"
dataKey="allowed"
stroke="#71ADFE"
connectNulls={true}
activeDot={{ r: 8 }}
strokeWidth={strokeWidth.allowed}
/>
<Line
type="monotone"
connectNulls={true}
dataKey="blocked"
stroke="#EB5757"
activeDot={{ r: 8 }}
strokeWidth={strokeWidth.blocked}
/>
</LineChart>
</ResponsiveContainer>
);
}
Example #18
Source File: PoolComposition.tsx From mStable-apps with GNU Lesser General Public License v3.0 | 5 votes |
PoolComposition: FC = () => {
const { masset, fasset } = useSelectedFeederPoolState()
const data = useMemo(
() => [
{
name: masset.token.symbol,
value: masset.totalVaultInMasset.simple,
fill: assetColorMapping[masset.token.symbol] ?? '#444',
},
{
name: fasset.token.symbol,
value: fasset.totalVaultInMasset.simple,
fill: assetColorMapping[fasset.token.symbol] ?? '#888',
},
],
[masset, fasset],
)
return (
<RechartsContainer>
<ResponsiveContainer aspect={2}>
<PieChart margin={MARGIN}>
<Pie dataKey="value" isAnimationActive={false} data={data} fill="fill" />
<Legend align="left" layout="vertical" verticalAlign="middle" />
<Tooltip
formatter={toK as never}
separator=" "
contentStyle={{
fontSize: '14px',
padding: '8px',
background: 'rgba(255, 255, 255, 0.8)',
textAlign: 'right',
border: 'none',
borderRadius: '4px',
color: Color.black,
}}
wrapperStyle={{
top: 0,
left: 0,
}}
/>
</PieChart>
</ResponsiveContainer>
</RechartsContainer>
)
}
Example #19
Source File: QueueMetricsChart.tsx From asynqmon with MIT License | 5 votes |
function QueueMetricsChart(props: Props) {
const theme = useTheme();
const data = toChartData(props.data);
const keys = props.data.map((x) => x.metric.queue);
return (
<ResponsiveContainer height={260}>
<LineChart data={data}>
<CartesianGrid strokeDasharray="3 3" />
<XAxis
minTickGap={10}
dataKey="timestamp"
domain={[props.startTime, props.endTime]}
tickFormatter={(timestamp: number) =>
new Date(timestamp * 1000).toLocaleTimeString()
}
type="number"
scale="time"
stroke={theme.palette.text.secondary}
/>
<YAxis
tickFormatter={props.yAxisTickFormatter}
stroke={theme.palette.text.secondary}
/>
<Tooltip
labelFormatter={(timestamp: number) => {
return new Date(timestamp * 1000).toLocaleTimeString();
}}
/>
<Legend />
{keys.map((key, idx) => (
<Line
key={key}
type="monotone"
dataKey={key}
stroke={lineColors[idx % lineColors.length]}
dot={false}
/>
))}
</LineChart>
</ResponsiveContainer>
);
}
Example #20
Source File: StatisticsChart.tsx From jitsu with MIT License | 5 votes |
StatisticsChart: React.FC<Props> = ({
data,
granularity,
dataToDisplay = ["success", "skip", "errors"],
legendLabels = {},
}) => {
const [state, dispatch] = useReducer(reducer, initialState)
const handleClickOnLegend = (data: any) => {
const clickedDataType = data["value"] as DataType
dispatch({ type: clickedDataType })
}
return (
<ResponsiveContainer width="100%" minHeight={225} minWidth={300}>
<LineChart
className={styles.chart}
data={data.map(point => ({
...point,
date: granularity == "hour" ? point.date.format("HH:mm") : point.date.format("DD MMM"),
}))}
>
<XAxis dataKey="date" tick={<CustomizedXAxisTick />} stroke="#394e5a" />
<YAxis tick={<CustomizedYAxisTick />} stroke="#394e5a" />
<CartesianGrid strokeDasharray="3 3" stroke="#394e5a" />
<Legend onClick={handleClickOnLegend} formatter={value => legendLabels[value] ?? value} />
<Tooltip
wrapperStyle={{
backgroundColor: "#22313a",
border: "1px solid #394e5a",
}}
itemStyle={{ color: "#9bbcd1" }}
labelStyle={{ color: "#dcf3ff" }}
formatter={value => new Intl.NumberFormat("en").format(value)}
/>
{dataToDisplay.includes("total") && (
<Line dataKey="total" stroke={"rgb(135, 138, 252)"} hide={state.hide_total_data} {...commonLineProps} />
)}
{dataToDisplay.includes("success") && (
<Line dataKey="success" stroke={"#2cc56f"} hide={state.hide_success_data} {...commonLineProps} />
)}
{dataToDisplay.includes("skip") && (
<Line dataKey="skip" stroke={"#ffc021"} hide={state.hide_skip_data} {...commonLineProps} />
)}
{dataToDisplay.includes("errors") && (
<Line dataKey="errors" stroke={"#e53935"} hide={state.hide_errors_data} {...commonLineProps} />
)}
</LineChart>
</ResponsiveContainer>
)
}
Example #21
Source File: index.tsx From korona-info with MIT License | 4 votes |
Index: NextPage<{ groupedCoronaData: GroupedData, hospitalised: HospitalData[] }> = ({
groupedCoronaData, hospitalised
}: {
groupedCoronaData: GroupedData;
hospitalised: HospitalData[];
}) => {
const [selectedHealthCareDistrict, selectHealthCareDistrict] = useState<
string
>('all');
const confirmed = groupedCoronaData[selectedHealthCareDistrict].confirmed;
const deaths = groupedCoronaData[selectedHealthCareDistrict].deaths;
const recovered = groupedCoronaData[selectedHealthCareDistrict].recovered;
const allConfirmed = groupedCoronaData.all.confirmed;
const toast = useToast()
const latestInfection = confirmed.length
? format(
utcToZonedTime(
new Date(confirmed[confirmed.length - 1].date),
timeZone
),
'dd.MM.yyyy - HH:mm',
{ timeZone }
)
: null;
const latestInfectionDistrict =
confirmed[confirmed.length - 1]?.healthCareDistrict;
const latestDeath = deaths.length
? format(
utcToZonedTime(new Date(deaths[deaths.length - 1].date), timeZone),
'd.M.yyyy'
)
: null;
const latestDeathDistrict = deaths.length
? deaths[deaths.length - 1].area
: null;
const latestRecoveredDistrict = recovered.length
? recovered[recovered.length - 1].healthCareDistrict
: null;
const latestRecovered = recovered.length
? format(
utcToZonedTime(
new Date(recovered[recovered.length - 1].date),
timeZone
),
'd.M.yyyy'
)
: null;
const infectionsToday = getInfectionsToday(confirmed);
const [cumulativeChartScale, setCumulativeChartScale] = useState<
'linear' | 'log'
>('linear');
const [forecastChartScale, setForecaseChartScale] = useState<
'linear' | 'log'
>('linear');
// Map data to show development of infections
const {
infectionDevelopmentData,
infectionDevelopmentData30Days
} = groupedCoronaData[selectedHealthCareDistrict].timeSeries;
const maxValues =
infectionDevelopmentData30Days[infectionDevelopmentData30Days.length - 1];
const dataMaxValue = Math.max(
maxValues?.deaths ?? 0,
maxValues?.infections ?? 0,
maxValues?.infections ?? 0
);
const {
infectionsByDistrict,
infectionsByDistrictPercentage,
areas
} = getTnfectionsByDistrict(allConfirmed);
const { infectionsBySourceCountry } = getInfectionsBySourceCountry(confirmed);
const networkGraphData = getNetworkGraphData(confirmed);
const { t } = useContext(UserContext);
const humanizeHealthcareDistrict = (district: string) => {
if (district === 'all') {
return t('All healthcare districts');
} else if (district === 'unknown') {
return t('unknown');
} else {
return district;
}
};
const reversedConfirmed = confirmed
// @ts-ignore
.map((i, index) => ({
index: index + 1,
...i,
healthCareDistrict: humanizeHealthcareDistrict(i.healthCareDistrict)
}))
.reverse();
const humanizedHealthCareDistrict = humanizeHealthcareDistrict(
selectedHealthCareDistrict
);
useEffect(() => {
if (typeof window !== undefined) {
toast({
position: 'bottom',
title: 'Datan lähteenä nyt THL',
description: 'HS:n datan lähde on vaihtunut THL:ään. THL:n tiedotussyklistä johtuen tiedot päivittyvät aiempaa harvemmin. Myös vanhemmissa tapauksissa voi olla päivämääräkohtaisia eroja, johtuen muuttuneesta raportointitavasta.',
status: "info",
isClosable: true,
duration: 14000,
});
}
}, [])
return (
<>
<Head>
<title>
{t('finland corona status')} - {t('cases')} : {confirmed.length || 0}{' '}
- {t('recovered')}: {recovered.length || 0} - {t('deaths')}:{' '}
{deaths.length || 0}
</title>
<meta
name="description"
content={`Suomen koronavirus-tartuntatilanne – tartunnat: ${confirmed.length ||
0} - parantuneet: ${recovered.length ||
0} - menehtyneet: ${deaths.length || 0}`}
/>
<meta property="og:title" content={t('finland corona status')} />
<meta
property="og:description"
content={`Tartuntoja tällä hetkellä: ${confirmed.length ||
0} - parantuneet: ${recovered.length ||
0} - menehtyneet: ${deaths.length || 0}`}
/>
<meta
property="og:site_name"
content="Suomen koronavirus-tartuntatilanne"
/>
<meta property="og:locale" content="fi_FI" />
<meta property="og:type" content="website" />
<meta property="og:image" content="/images/corona-virus.png" />
<meta property="og:image:width" content="1920" />
<meta property="og:image:height" content="1928" />
<meta property="og:url" content="https://korona.kans.io" />
</Head>
<Layout>
<Flex
alignItems="center"
flexDirection="column"
flex="1"
width={'100%'}
maxWidth="1440px"
margin="auto"
>
<Header />
<Flex
flexWrap="wrap"
flexDirection="row"
justifyContent="left"
alignItems="stretch"
flex="1"
width={'100%'}
>
<Box width={['100%', '100%', 1 / 3, 1 / 3]} p={3}>
<Select
value={selectedHealthCareDistrict ?? undefined}
onChange={event => selectHealthCareDistrict(event.target.value)}
>
<option key={'all'} value={'all'}>
{t('All healthcare districts')}
</option>
{healtCareDistricts.map(healthcareDistrict => (
<option
key={healthcareDistrict.name}
value={healthcareDistrict.name}
>
{healthcareDistrict.name}
</option>
))}
))}
</Select>
</Box>
</Flex>
<Flex
flexWrap="wrap"
flexDirection="row"
justifyContent="center"
alignItems="stretch"
flex="1"
width={'100%'}
>
<Box width={['100%', '100%', 1 / 2, 1 / 2]} p={3}>
<Block
title={t('cases') + ` (${humanizedHealthCareDistrict})`}
textAlign="center"
extraInfo={`${t('New cases today')} ${infectionsToday} ${t(
'person'
)}`}
footer={`${t(
'latest case'
)} ${latestInfection} (${humanizeHealthcareDistrict(
latestInfectionDistrict
)})`}
>
<StatBlock
count={confirmed.length}
helpText={`${t('New cases today')}: ${infectionsToday} ${t(
'person'
)}`}
/>
</Block>
</Box>
<Box width={['100%', '100%', 1 / 2, 1 / 2]} p={3}>
<Block
title={t('deaths') + ` (${humanizedHealthCareDistrict})`}
footer={
latestDeath
? `${t(
'last death'
)} ${latestDeath} (${humanizeHealthcareDistrict(
latestDeathDistrict!
)})`
: t('no death')
}
>
<StatBlock count={deaths.length || 0} />
</Block>
</Box>
{/* <Box width={['100%', '100%', 1 / 3, 1 / 3]} p={3}>
<Block
title={t('recovered') + ` (${humanizedHealthCareDistrict})`}
footer={
`${latestRecovered
? `${t(
'latest recovery'
)} ${latestRecovered} (${humanizeHealthcareDistrict(latestRecoveredDistrict!)}).`
: ' '} ${t('recoveredNotice')}`}
>
<StatBlock count={recovered.length || 0} />
</Block>
</Box> */}
<Box width={['100%']} p={3}>
<Block
title={
t('accumulated change') + ` (${humanizedHealthCareDistrict})`
}
footer={t('cases recovered and death in past 30 days')}
>
<ButtonGroup
spacing={0}
alignSelf="center"
display="flex"
justifyContent="center"
marginTop="-15px"
>
<Button
size="xs"
fontFamily="Space Grotesk Regular"
px={3}
letterSpacing="1px"
borderRadius="4px 0px 0px 4px"
borderWidth="0px"
isActive={cumulativeChartScale === 'linear'}
onClick={() => setCumulativeChartScale('linear')}
>
{t('linear')}
</Button>
<Button
size="xs"
fontFamily="Space Grotesk Regular"
px={3}
letterSpacing="1px"
borderRadius="0px 4px 4px 0px"
borderWidth="0px"
isActive={cumulativeChartScale === 'log'}
onClick={() => setCumulativeChartScale('log')}
>
{t('logarithmic')}
</Button>
</ButtonGroup>
<ResponsiveContainer width={'100%'} height={380}>
<ComposedChart
data={
cumulativeChartScale === 'log'
? infectionDevelopmentData30Days.map(zerosToNulls)
: infectionDevelopmentData30Days
}
margin={{ top: 20, right: 30, left: 0, bottom: 30 }}
>
<defs>
<linearGradient
id="colorInfection"
x1="0"
y1="0"
x2="0"
y2="1"
>
<stop
offset="5%"
stopColor={colors[8]}
stopOpacity={0.6}
/>
<stop
offset="95%"
stopColor={colors[8]}
stopOpacity={0}
/>
</linearGradient>
<linearGradient
id="colorRecovered"
x1="0"
y1="0"
x2="0"
y2="1"
>
<stop
offset="5%"
stopColor={colors[7]}
stopOpacity={0.6}
/>
<stop
offset="95%"
stopColor={colors[7]}
stopOpacity={0}
/>
</linearGradient>
<linearGradient
id="colorDeaths"
x1="0"
y1="0"
x2="0"
y2="1"
>
<stop
offset="5%"
stopColor={colors[0]}
stopOpacity={0.6}
/>
<stop
offset="95%"
stopColor={colors[0]}
stopOpacity={0}
/>
</linearGradient>
</defs>
<XAxis
tickFormatter={d => format(new Date(d), 'd.M.')}
tick={<CustomizedAxisTick isDate />}
dataKey="date"
domain={['dataMin', 'dataMax']}
type="number"
scale="time"
/>
<YAxis
scale={cumulativeChartScale}
dataKey="infections"
domain={[
cumulativeChartScale === 'log' ? 1 : 0,
dataMaxValue + 10
]}
unit={' ' + t('person')}
tick={{ fontSize: 12 }}
name={t('cases')}
/>
<CartesianGrid opacity={0.2} />
<Tooltip
labelFormatter={v => format(new Date(v), 'dd.MM.yyyy')}
/>
<Bar
isAnimationActive={false}
fill={colors[1]}
opacity={0.4}
dataKey="infectionsDaily"
name={t('cases of the day')}
unit={' ' + t('person')}
/>
<Area
isAnimationActive={false}
type="monotone"
unit={' ' + t('person')}
name={t('total cases')}
dataKey="infections"
stroke={colors[8]}
fillOpacity={1}
fill="url(#colorInfection)"
/>
{/* <Area
isAnimationActive={false}
type="monotone"
unit={' ' + t('person')}
name={t('total recovered')}
dataKey="recovered"
stroke={colors[7]}
fillOpacity={1}
fill="url(#colorRecovered)"
/> */}
<Area
isAnimationActive={false}
type="monotone"
unit={' ' + t('person')}
name={t('total deaths')}
dataKey="deaths"
stroke={colors[0]}
fillOpacity={1}
fill="url(#colorDeaths)"
/>
<Legend wrapperStyle={{ bottom: '10px' }} />
</ComposedChart>
</ResponsiveContainer>
</Block>
</Box>
{/*
<Box width={['100%']} p={3}>
<Block title="Tartuntojen kumulatiivinen ennustemalli" footer={`Tartuntojen kehityksen ennustemalli 60 päivää. Laskee ennustetun eksponentiaalisen kasvun käyttämällä aiemmin luotuja tietoja. Käytetty <a style="color: #319795;" href="https://github.com/mljs/regression-exponential" target="_blank">exponential-regression</a> kirjastoa.`}>
<ButtonGroup spacing={0} alignSelf="center" display="flex" justifyContent="center" marginTop="-15px">
<Button size="xs" fontFamily="Space Grotesk Regular" px={3} letterSpacing="1px" borderRadius="4px 0px 0px 4px" borderWidth="0px" isActive={forecastChartScale === 'linear'} onClick={() => setForecaseChartScale('linear')}>
Lineaarinen
</Button>
<Button size="xs" fontFamily="Space Grotesk Regular" px={3} letterSpacing="1px" borderRadius="0px 4px 4px 0px" borderWidth="0px" isActive={forecastChartScale === 'log'} onClick={() => setForecaseChartScale('log')}>
Logaritminen
</Button>
</ButtonGroup>
<ResponsiveContainer width={'100%'} height={350}>
<AreaChart
data={prediction60Days}
margin={{ top: 20, right: 30, left: 0, bottom: 20 }}
>
<defs>
<linearGradient id="colorInfection" x1="0" y1="0" x2="0" y2="1">
<stop offset="5%" stopColor={colors[8]} stopOpacity={0.6} />
<stop offset="95%" stopColor={colors[8]} stopOpacity={0} />
</linearGradient>
</defs>
<XAxis tickFormatter={d => format(new Date(d), 'd.M.')} tick={<CustomizedAxisTick isDate />} dataKey="date" domain={['dataMin', 'dataMax']} type="number" scale="time" />
<YAxis scale={forecastChartScale} dataKey="infections" domain={['auto', 'auto']} unit={' ' + t('person') } tick={{ fontSize: 12 }} name="Tartunnat" />
<CartesianGrid opacity={0.2} />
<ReferenceLine
x={today}
stroke="rgba(0,0,0,.5)"
// @ts-ignore
label={{ position: 'top', value: 'Nyt', fill: 'rgba(0,0,0,0.5)', fontSize: 12 }}
strokeDasharray="3 3" />
<Tooltip labelFormatter={v => format(new Date(v), 'dd.MM.yyyy')} />
<Area type="monotone" name="Ennuste" unit={' ' + t('person') } dataKey="infections" stroke={colors[8]} fillOpacity={1} fill="url(#colorInfection)" />
</AreaChart>
</ResponsiveContainer>
</Block>
</Box>
*/}
<Box width={['100%', '100%', '100%', '100%', 1 / 2]} p={3}>
<Block
title={t('Cases by district')}
footer={t('Helsinki metropolitan area is shown as HUS')}
>
<ResponsiveContainer width={'100%'} height={350}>
<BarChart
data={infectionsByDistrict}
margin={{
top: 20,
right: 30,
left: 0,
bottom: 85
}}
>
<XAxis
interval={0}
dataKey="name"
tick={<CustomizedAxisTick />}
/>
<YAxis
yAxisId="left"
unit={' ' + t('person')}
dataKey="infections"
tick={{ fontSize: 12 }}
/>
<Tooltip />
<Bar
isAnimationActive={false}
dataKey="infections"
name={t('cases')}
unit={' ' + t('person')}
yAxisId="left"
>
{areas.map((area, index) => (
<Cell key={area} fill={colors[index % colors.length]} />
))}
<LabelList
dataKey="infections"
position="top"
formatter={e => e}
/>
</Bar>
</BarChart>
</ResponsiveContainer>
</Block>
</Box>
<Box width={['100%', '100%', '100%', '100%', 1 / 2]} p={3}>
<Block
title={t('infectionsPerDisrictAndSize')}
footer={t('infectionsPerDisrictAndSize')}
>
<ResponsiveContainer width={'100%'} height={350}>
<BarChart
data={infectionsByDistrictPercentage}
margin={{
top: 20,
right: 30,
left: 0,
bottom: 85
}}
>
<XAxis
interval={0}
dataKey="name"
tick={<CustomizedAxisTick />}
/>
<YAxis
unit=" %"
dataKey="perDistrict"
tick={{ fontSize: 12 }}
/>
<Tooltip />
<Bar isAnimationActive={false} dataKey="perDistrict" name="%-osuus väestöstä" unit=" %">
{areas.map((area, index) => (
<Cell key={area} fill={colors[index % colors.length]} />
))}
<LabelList
dataKey="perDistict"
position="top"
formatter={e => e}
/>
</Bar>
</BarChart>
</ResponsiveContainer>
</Block>
</Box>
<Box width={['100%', '100%', '100%', '100%', 1 / 2]} p={3}>
<Block
title={t('log') + ` (${humanizedHealthCareDistrict})`}
footer={t('logFooter')}
>
<Table
height={500}
data={reversedConfirmed}
columns={useMemo(() => infectionColumns, [])}
/>
</Block>
</Box>
<BubbleChart data={groupedCoronaData} />
{/* <Box width={['100%', '100%', '100%', '100%', 1 / 2]} p={3}>
<Block
title={
t('infectionNetwork') + ` (${humanizedHealthCareDistrict})`
}
footer={t('infectionNetworkFooter')}
>
<NetworkGraph data={networkGraphData} />
</Block>
</Box> */}
<Box width={['100%']} p={3}>
<Block
title={
t('hospitalizedData') + ` (${t('All healthcare districts')})`
}
>
<ResponsiveContainer width={'100%'} height={350}>
<BarChart
data={hospitalised.slice(Math.max(hospitalised.length - 30, 0))}
margin={{
top: 20,
right: 30,
left: 0,
bottom: 85
}}
>
<XAxis
interval={0}
dataKey="dateString"
tick={<CustomizedAxisTick />}
padding={{ left: 50, right: 50 }}
/>
<YAxis
unit={' ' + t('person')}
dataKey="totalHospitalised"
tick={{ fontSize: 12 }}
/>
<Tooltip />
<Bar
isAnimationActive={false}
stackId="a"
dataKey="inIcu"
name={t("inIcu")}
unit={' ' + t('person')}
fill="#F3858D"
/>
<Bar
isAnimationActive={false}
stackId="a"
dataKey="inWard"
name={t("inWard")}
unit={' ' + t('person')}
fill="#2FAB8E"
/>
<Bar
isAnimationActive={false}
stackId="a"
dataKey="totalHospitalised"
opacity={0}
name={t("inHospital")}
unit={' ' + t('person')}
fill="rgba(0,0,0,1)"
strokeWidth={0}
legendType="none"
/>
<Legend wrapperStyle={{ bottom: '15px' }} />
</BarChart>
</ResponsiveContainer>
</Block>
</Box>
</Flex>
<Copyright />
</Flex>
</Layout>
</>
);
}
Example #22
Source File: index.tsx From livepeer-com with MIT License | 4 votes |
Chart = ({
data,
multiData,
}: {
data: Array<{ name: number; "Session bitrate": number }>;
multiData?: Array<{
[name: string]: number;
}>;
}) => {
const multistreamNames =
multiData && multiData[0] && Object.keys(multiData[0]);
return (
<Box
css={{
width: "100%",
position: "relative",
".recharts-cartesian-axis-tick": {
fontSize: "$2",
},
}}>
<Text
variant="gray"
size="1"
css={{
transform: "rotate(-90deg)",
position: "absolute",
left: "-70px",
bottom: "70px",
}}>
kbps (multiplied by 1000)
</Text>
<Text
variant="gray"
size="1"
css={{
position: "absolute",
bottom: "-30px",
left: "50px",
}}>
Seconds since stream loaded
</Text>
<ResponsiveContainer width="99%" height={300}>
<LineChart>
<XAxis
type="number"
dataKey="name"
domain={[
data[0]?.name,
data.length < 2 ? 10 : data[data.length - 1].name,
]}
tickCount={7}
allowDataOverflow
/>
<YAxis domain={[0, 1600]} />
<CartesianGrid vertical={false} />
<Tooltip content={<CustomTooltip />} />
<Legend wrapperStyle={{ fontSize: "10px" }} />
<Line
data={data}
cursor="pointer"
type="monotone"
dataKey="Session bitrate"
stroke="#5746AF"
strokeWidth="2px"
/>
{multistreamNames?.map((item, index) => {
if (item !== "name")
return (
<Line
data={multiData}
cursor="pointer"
type="monotone"
dataKey={item}
stroke={getMultistreamColor(index)}
strokeWidth="2px"
/>
);
})}
</LineChart>
</ResponsiveContainer>
</Box>
);
}
Example #23
Source File: index.tsx From liferay-grow with MIT License | 4 votes |
SkillDetailSummay: React.FC<SkillDetailSummaryProps> = ({
slug,
summary,
}) => {
const i18n = useLang();
const [visible, setVisible] = useState(false);
const [matriz, setMatriz] = useState<Summary>({} as Summary);
const { observer, onClose } = useModal({
onClose: () => setVisible(!visible),
});
// Filter Empty Results from Summary
const summaryData = summary.filter(({ value }) => value);
const getFromattedTooltip = (value: number) => {
const valueString = value.toString();
return i18n.sub(value > 1 ? 'x-members' : 'x-member', valueString);
};
const hasSummary = !!summaryData.length;
return (
<Panel displayType="unstyled" title={i18n.get('summary')}>
{hasSummary ? (
<>
<PieChart className="summary-chart" width={420} height={280}>
<Pie
data={summaryData}
dataKey="value"
nameKey="name"
cx="50%"
cy="50%"
innerRadius={70}
outerRadius={120}
paddingAngle={0}
>
{summary.map((_, index) => (
<Cell
key={index}
fill={COLORS[index]}
onClick={() => console.log(summary)}
/>
))}
</Pie>
<Tooltip formatter={getFromattedTooltip} />
<Legend
align="right"
iconSize={16}
formatter={(value) => (
<ClayButton
displayType="unstyled"
onClick={() => {
setVisible(true);
const matriz = summary.find(({ name }) => name === value);
setMatriz(matriz);
}}
>
<span className="legend-text">{value}</span>
</ClayButton>
)}
iconType="square"
layout="vertical"
verticalAlign="middle"
/>
</PieChart>
<Modal
visible={visible}
observer={observer}
title={matriz.name}
subtitle={
matriz.description
? `${i18n.sub('description-x-x', [
matriz.name,
matriz.description,
])}`
: null
}
>
<ListMembers onClose={onClose} matriz={matriz} slug={slug} />
</Modal>
</>
) : (
<EmptyState title={i18n.get('there-are-no-members-yet')} />
)}
</Panel>
);
}
Example #24
Source File: ChartDetailsArea.tsx From kubenav with MIT License | 4 votes |
ChartDetailsArea: React.FunctionComponent<IChartDetailsAreaProps> = ({
unit,
timeDiff,
results,
}: IChartDetailsAreaProps) => {
const context = useContext<IContext>(AppContext);
const [selected, setSelected] = useState<string>('');
// formatTime is use to formate the shown values for the x axis. If the user selected a time span lower then 24h we
// are showing the "hh:mm" for timespans larger then 24h we are showing "MM/DD hh:mm".
const formatTime = (time: number): string => {
const d = new Date(time * 1000);
if (timeDiff >= 86400) {
return `${('0' + (d.getMonth() + 1)).slice(-2)}/${('0' + d.getDate()).slice(-2)} ${('0' + d.getHours()).slice(
-2,
)}:${('0' + d.getMinutes()).slice(-2)}`;
} else {
return `${('0' + d.getHours()).slice(-2)}:${('0' + d.getMinutes()).slice(-2)}`;
}
};
// The series variables contains the transformed Prometheus results. This is necessary, because the returned formate
// from Prometheus can not directly used with Recharts.
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const series: any = [];
for (let i = 0; i < results.length; i++) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const data: any = [];
for (let j = 0; j < results[i].values.length; j++) {
data.push({
time: results[i].values[j][0],
value: parseFloat(results[i].values[j][1]),
});
}
series.push({ name: results[i].label, data: data });
}
return (
<IonRow style={{ height: '300px', width: '100%' }}>
<IonCol style={{ padding: '0px' }}>
<ResponsiveContainer>
<AreaChart data={series[0].data}>
<XAxis
dataKey="time"
scale="time"
type="number"
domain={['dataMin', 'dataMax']}
tickFormatter={formatTime}
/>
<YAxis dataKey="value" unit={unit} />
<Legend
height={40}
wrapperStyle={{ overflowY: 'auto' }}
onClick={(e) => (selected === e.payload.name ? setSelected('') : setSelected(e.payload.name))}
/>
{!isPlatform('hybrid') ? (
<Tooltip
cursor={{ stroke: '#949494', strokeWidth: 2 }}
contentStyle={
isDarkMode(context.settings.theme)
? isPlatform('ios')
? { backgroundColor: '1c1c1c', borderColor: '#949494' }
: { backgroundColor: '#1A1B1E', borderColor: '#949494' }
: { backgroundColor: '#ffffff', borderColor: '#949494' }
}
formatter={(value) => {
return `${value.toFixed(5)} ${unit ? unit : ''}`;
}}
labelFormatter={formatTime}
/>
) : null}
{selected === ''
? series.map((serie, index) => (
<Area
key={index}
dataKey="value"
// NOTE: https://github.com/recharts/recharts/issues/2487
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
data={serie.data}
name={serie.name}
stroke={getColor(index, isDarkMode(context.settings.theme))}
fill={getColor(index, isDarkMode(context.settings.theme))}
fillOpacity={0.2}
/>
))
: series
.filter((serie) => serie.name === selected)
.map((serie, index) => (
<Area
key={index}
dataKey="value"
// NOTE: https://github.com/recharts/recharts/issues/2487
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
data={serie.data}
name={serie.name}
stroke={getColor(
series.findIndex((s) => s.name === selected),
isDarkMode(context.settings.theme),
)}
fill={getColor(
series.findIndex((s) => s.name === selected),
isDarkMode(context.settings.theme),
)}
fillOpacity={0.2}
/>
))}
</AreaChart>
</ResponsiveContainer>
</IonCol>
</IonRow>
);
}
Example #25
Source File: BalanceHistoryGraph.tsx From abrechnung with GNU Affero General Public License v3.0 | 4 votes |
export default function BalanceHistoryGraph({ group, accountID }) {
const theme: Theme = useTheme();
const balanceHistory = useRecoilValue(accountBalanceHistory({ groupID: group.id, accountID: accountID }));
const history = useHistory();
const transactionMap = useRecoilValue(transactionByIDMap(group.id));
const accountMap = useRecoilValue(accountByIDMap(group.id));
const onClick = (evt) => {
if (evt.activePayload.length > 0) {
const payload = evt.activePayload[0].payload;
if (payload.changeOrigin.type === "clearing") {
history.push(`/groups/${group.id}/accounts/${payload.changeOrigin.id}`);
} else {
history.push(`/groups/${group.id}/transactions/${payload.changeOrigin.id}`);
}
}
};
const renderTooltip = ({ payload, label, active }) => {
if (!active) {
return null;
}
const changeOrigin = payload[0].payload.changeOrigin;
const icon =
changeOrigin.type === "clearing" ? (
<ClearingAccountIcon color="primary" fontSize="small" />
) : transactionMap[changeOrigin.id].type === "purchase" ? (
<PurchaseIcon color="primary" sx={{ fontSize: theme.typography.fontSize }} />
) : (
<TransferIcon color="primary" fontSize="small" />
);
return (
<Box
sx={{
backgroundColor: theme.palette.background.paper,
borderColor: theme.palette.divider,
borderRadius: theme.shape.borderRadius,
borderWidth: "1px",
borderStyle: "solid",
padding: 2,
}}
>
<div style={{ display: "flex", justifyContent: "space-between" }}>
<Typography variant="body1" component="span">
{DateTime.fromSeconds(payload[0].payload.date).toISODate()} {icon}
</Typography>
<Typography
component="span"
sx={{ color: (theme) => balanceColor(payload[0].value, theme), ml: 2 }}
>
{payload[0].value} {group.currency_symbol}
</Typography>
</div>
<Divider />
{payload[0].payload.changeOrigin.type === "clearing" ? (
<Typography variant="body1">{accountMap[payload[0].payload.changeOrigin.id].name}</Typography>
) : (
<Typography variant="body1">
{transactionMap[payload[0].payload.changeOrigin.id].description}
</Typography>
)}
</Box>
);
};
return (
<ResponsiveContainer width="100%" height={300}>
<LineChart
width={730}
height={250}
onClick={onClick}
data={balanceHistory}
margin={{
top: 5,
right: 30,
left: 20,
bottom: 5,
}}
>
<CartesianGrid strokeDasharray="3 3" />
<XAxis
dataKey="date"
stroke={theme.palette.text.primary}
type="number"
tickFormatter={(unixTime) => DateTime.fromSeconds(unixTime).toISODate()}
domain={["dataMin", "dataMax"]}
/>
<YAxis
tickFormatter={(value) => value.toFixed(2)}
type="number"
unit={group.currency_symbol}
stroke={theme.palette.text.primary}
/>
<Tooltip content={renderTooltip} />
<Legend />
<Line type="stepAfter" dataKey="balance" />
</LineChart>
</ResponsiveContainer>
);
}
Example #26
Source File: stage-chart.tsx From backstage with Apache License 2.0 | 4 votes |
export function StageChart(props: StageChartProps) {
const { stage, ...chartOptions } = props;
const {
chartTypes,
defaultCollapsed = 0,
defaultHidden = 0,
zeroYAxis = false,
} = chartOptions;
const { zoomFilterValues } = useZoom();
const { zoomProps, getZoomArea } = useZoomArea();
const ticks = useMemo(
() => pickElements(stage.values, 8).map(val => val.__epoch),
[stage.values],
);
const domainY = useMemo(
() => [zeroYAxis ? 0 : 'auto', 'auto'] as YAxisProps['domain'],
[zeroYAxis],
);
const statuses = useMemo(
() => statusTypes.filter(status => stage.statusSet.has(status)),
[stage.statusSet],
);
const legendPayload = useMemo(
(): LegendProps['payload'] =>
statuses.map(status => ({
value: capitalize(status),
type: 'line',
id: status,
color: statusColorMap[status],
})),
[statuses],
);
const subStages = useMemo(
() =>
new Map<string, ChartableStage>(
[...stage.stages.entries()].filter(
([_name, subStage]) => subStage.combinedAnalysis.max > defaultHidden,
),
),
[stage.stages, defaultHidden],
);
const zoomFilteredValues = useMemo(
() => zoomFilterValues(stage.values),
[stage.values, zoomFilterValues],
);
return stage.combinedAnalysis.max < defaultHidden ? null : (
<Accordion
defaultExpanded={stage.combinedAnalysis.max > defaultCollapsed}
TransitionProps={transitionProps}
>
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
<Typography>
{stage.name} (med {formatDuration(stage.combinedAnalysis.med)}, avg{' '}
{formatDuration(stage.combinedAnalysis.avg)})
</Typography>
</AccordionSummary>
<AccordionDetails>
{stage.values.length === 0 ? (
<Alert severity="info">No data</Alert>
) : (
<Grid container direction="column">
<Grid item style={noUserSelect}>
<ResponsiveContainer width="100%" height={140}>
<ComposedChart data={zoomFilteredValues} {...zoomProps}>
<defs>
<linearGradient id="colorDur" x1="0" y1="0" x2="0" y2="1">
{fireColors.map(([percent, color]) => (
<stop
key={percent}
offset={percent}
stopColor={color}
stopOpacity={0.8}
/>
))}
</linearGradient>
</defs>
{statuses.length > 1 && <Legend payload={legendPayload} />}
<CartesianGrid strokeDasharray="3 3" />
<XAxis
dataKey="__epoch"
type="category"
ticks={ticks}
tickFormatter={tickFormatterX}
/>
<YAxis
yAxisId={1}
tickFormatter={tickFormatterY}
type="number"
tickCount={5}
name="Duration"
domain={domainY}
/>
<YAxis
yAxisId={2}
orientation="right"
type="number"
tickCount={5}
name="Count"
/>
<Tooltip
formatter={tooltipValueFormatter}
labelFormatter={labelFormatter}
/>
{statuses.reverse().map(status => (
<Fragment key={status}>
{!chartTypes[status].includes('duration') ? null : (
<>
<Area
isAnimationActive={false}
yAxisId={1}
type="monotone"
dataKey={status}
stackId={status}
stroke={
statuses.length > 1
? statusColorMap[status]
: colorStroke
}
fillOpacity={statuses.length > 1 ? 0.5 : 1}
fill={
statuses.length > 1
? statusColorMap[status]
: 'url(#colorDur)'
}
connectNulls
/>
<Line
isAnimationActive={false}
yAxisId={1}
type="monotone"
dataKey={`${status} avg`}
stroke={
statuses.length > 1
? statusColorMap[status]
: colorStrokeAvg
}
opacity={0.8}
strokeWidth={2}
dot={false}
connectNulls
/>
</>
)}
{!chartTypes[status].includes('count') ? null : (
<Bar
isAnimationActive={false}
yAxisId={2}
type="monotone"
dataKey={`${status} count`}
stackId="1"
stroke={statusColorMap[status] ?? ''}
fillOpacity={0.5}
fill={statusColorMap[status] ?? ''}
/>
)}
</Fragment>
))}
{getZoomArea({ yAxisId: 1 })}
</ComposedChart>
</ResponsiveContainer>
</Grid>
{subStages.size === 0 ? null : (
<Grid item>
<Accordion
defaultExpanded={false}
TransitionProps={transitionProps}
>
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
<Typography>Sub stages ({subStages.size})</Typography>
</AccordionSummary>
<AccordionDetails>
<div style={fullWidth}>
{[...subStages.values()].map(subStage => (
<StageChart
key={subStage.name}
{...chartOptions}
stage={subStage}
/>
))}
</div>
</AccordionDetails>
</Accordion>
</Grid>
)}
</Grid>
)}
</AccordionDetails>
</Accordion>
);
}
Example #27
Source File: status-chart.tsx From backstage with Apache License 2.0 | 4 votes |
export function StatusChart(props: StatusChartProps) {
const { analysis } = props;
const { zoomFilterValues } = useZoom();
const { zoomProps, getZoomArea } = useZoomArea();
const values = useMemo(() => {
return analysis.daily.values.map(value => {
const totTriggers = analysis.daily.triggerReasons.reduce(
(prev, cur) => prev + (value[cur as TriggerReason] ?? 0),
0,
);
if (!totTriggers) {
return value;
}
return {
...value,
...Object.fromEntries(
analysis.daily.triggerReasons.map(reason => [
reason,
(value[reason as TriggerReason] ?? 0) / totTriggers,
]),
),
};
});
}, [analysis.daily]);
const triggerReasonLegendPayload = useMemo(
(): NonNullable<LegendProps['payload']> =>
analysis.daily.triggerReasons.map(reason => ({
value: humanTriggerReason(reason),
type: 'line',
id: reason,
color: triggerColorMap[reason as TriggerReason] ?? '',
})),
[analysis.daily.triggerReasons],
);
const statusesLegendPayload = useMemo(
(): NonNullable<LegendProps['payload']> =>
analysis.daily.statuses.map(status => ({
value: capitalize(status),
type: 'line',
id: status,
color: statusColorMap[status as FilterStatusType] ?? '',
})),
[analysis.daily.statuses],
);
const legendPayload = useMemo(
(): NonNullable<LegendProps['payload']> => [
...triggerReasonLegendPayload,
...statusesLegendPayload,
],
[statusesLegendPayload, triggerReasonLegendPayload],
);
const tooltipFormatter = useMemo(() => {
const reasonSet = new Set(analysis.daily.triggerReasons);
return (percentOrCount: number, name: string) => {
const label = reasonSet.has(name)
? humanTriggerReason(name)
: capitalize(name);
const valueText = reasonSet.has(name)
? `${(percentOrCount * 100).toFixed(0)}%`
: percentOrCount;
return [
<span>
{label}: {valueText}
</span>,
null,
];
};
}, [analysis.daily.triggerReasons]);
const zoomFilteredValues = useMemo(
() => zoomFilterValues(values),
[values, zoomFilterValues],
);
const barSize = getBarSize(analysis.daily.values.length);
return (
<Accordion defaultExpanded={analysis.daily.statuses.length > 1}>
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
<Typography>
Build count per status over build trigger reason
</Typography>
</AccordionSummary>
<AccordionDetails>
{values.length === 0 ? (
<Alert severity="info">No data</Alert>
) : (
<ResponsiveContainer width="100%" height={140}>
<ComposedChart data={zoomFilteredValues} {...zoomProps}>
<Legend payload={legendPayload} />
<CartesianGrid strokeDasharray="3 3" />
<XAxis
dataKey="__epoch"
type="category"
tickFormatter={tickFormatterX}
/>
<YAxis yAxisId={1} type="number" tickCount={5} name="Count" />
<YAxis yAxisId={2} type="number" name="Triggers" hide />
<Tooltip
labelFormatter={labelFormatterWithoutTime}
formatter={tooltipFormatter}
/>
{triggerReasonLegendPayload.map(reason => (
<Fragment key={reason.id}>
<Area
isAnimationActive={false}
type="monotone"
dataKey={reason.id!}
stackId="triggers"
yAxisId={2}
stroke={triggerColorMap[reason.id as TriggerReason] ?? ''}
fillOpacity={0.5}
fill={triggerColorMap[reason.id as TriggerReason] ?? ''}
/>
</Fragment>
))}
{[...analysis.daily.statuses].reverse().map(status => (
<Fragment key={status}>
<Bar
isAnimationActive={false}
type="monotone"
barSize={barSize}
dataKey={status}
stackId="statuses"
yAxisId={1}
stroke={statusColorMap[status as FilterStatusType] ?? ''}
fillOpacity={0.8}
fill={statusColorMap[status as FilterStatusType] ?? ''}
/>
</Fragment>
))}
{getZoomArea({ yAxisId: 1 })}
</ComposedChart>
</ResponsiveContainer>
)}
</AccordionDetails>
</Accordion>
);
}
Example #28
Source File: CoverageHistoryChart.tsx From backstage with Apache License 2.0 | 4 votes |
CoverageHistoryChart = () => {
const { entity } = useEntity();
const codeCoverageApi = useApi(codeCoverageApiRef);
const {
loading: loadingHistory,
error: errorHistory,
value: valueHistory,
} = useAsync(
async () =>
await codeCoverageApi.getCoverageHistoryForEntity({
kind: entity.kind,
namespace: entity.metadata.namespace || 'default',
name: entity.metadata.name,
}),
);
const classes = useStyles();
if (loadingHistory) {
return <Progress />;
}
if (errorHistory) {
return <ResponseErrorPanel error={errorHistory} />;
} else if (!valueHistory) {
return <Alert severity="warning">No history found.</Alert>;
}
if (!valueHistory.history.length) {
return (
<Card>
<CardHeader title="History" />
<CardContent>No coverage history found</CardContent>
</Card>
);
}
const oldestCoverage = valueHistory.history[0];
const [latestCoverage] = valueHistory.history.slice(-1);
const getTrendForCoverage = (type: Coverage) => {
if (!oldestCoverage[type].percentage) {
return 0;
}
return (
((latestCoverage[type].percentage - oldestCoverage[type].percentage) /
oldestCoverage[type].percentage) *
100
);
};
const lineTrend = getTrendForCoverage('line');
const branchTrend = getTrendForCoverage('branch');
return (
<Card>
<CardHeader title="History" />
<CardContent>
<Box px={6} display="flex">
<Box display="flex" mr={4}>
{getTrendIcon(lineTrend, classes)}
<Typography>
Current line: {latestCoverage.line.percentage}%<br />(
{Math.floor(lineTrend)}% change over {valueHistory.history.length}{' '}
builds)
</Typography>
</Box>
<Box display="flex">
{getTrendIcon(branchTrend, classes)}
<Typography>
Current branch: {latestCoverage.branch.percentage}%<br />(
{Math.floor(branchTrend)}% change over{' '}
{valueHistory.history.length} builds)
</Typography>
</Box>
</Box>
<ResponsiveContainer width="100%" height={300}>
<LineChart
data={valueHistory.history}
margin={{ right: 48, top: 32 }}
>
<CartesianGrid strokeDasharray="3 3" />
<XAxis
dataKey="timestamp"
tickFormatter={formatDateToHuman}
reversed
/>
<YAxis dataKey="line.percentage" />
<YAxis dataKey="branch.percentage" />
<Tooltip labelFormatter={formatDateToHuman} />
<Legend />
<Line
type="monotone"
dataKey="branch.percentage"
stroke="#8884d8"
/>
<Line type="monotone" dataKey="line.percentage" stroke="#82ca9d" />
</LineChart>
</ResponsiveContainer>
</CardContent>
</Card>
);
}
Example #29
Source File: InDepth.tsx From backstage with Apache License 2.0 | 4 votes |
export function InDepth() {
const { releaseStats } = useReleaseStatsContext();
const { averageReleaseTime, progress, releaseCommitPairs, run } =
useGetReleaseTimes();
const skipped =
Object.keys(releaseStats.releases).length - releaseCommitPairs.length;
return (
<Box style={{ flex: 1 }}>
<Box margin={1}>
<Typography variant="h4">In-depth</Typography>
</Box>
<Box style={{ display: 'flex' }}>
<Box margin={1} style={{ display: 'flex', flex: 1 }}>
<Box>
<Typography variant="h6">Release time</Typography>
<Typography variant="body2">
<strong>Release time</strong> is derived by comparing{' '}
<i>createdAt</i> of the commits belonging to the first and last
tag of each release. Releases without patches will have tags
pointing towards the same commit and will thus be omitted. This
project will omit {skipped} out of the total{' '}
{Object.keys(releaseStats.releases).length} releases.
</Typography>
</Box>
</Box>
<Box
margin={1}
style={{ display: 'flex', flex: 1, flexDirection: 'column' }}
>
<Box>
<Typography variant="h6">In numbers</Typography>
<Typography variant="body2" color="textSecondary">
<strong>Average release time</strong>:{' '}
<AverageReleaseTime averageReleaseTime={averageReleaseTime} />
</Typography>
<Typography variant="body2" color="textSecondary">
<strong>Lengthiest release</strong>:{' '}
<LongestReleaseTime averageReleaseTime={averageReleaseTime} />
</Typography>
</Box>
<Box marginTop={1}>
{progress === 0 && (
<MaterialTooltip
title={`This action will send ~${
releaseCommitPairs.length * 2
} requests`}
>
<Button
variant="contained"
color="secondary"
onClick={() => run()}
size="small"
>
Crunch the numbers
</Button>
</MaterialTooltip>
)}
</Box>
</Box>
</Box>
<Box marginTop={4}>
<BarChart
width={700}
height={70 + averageReleaseTime.length * 22}
data={
averageReleaseTime.length > 0
? averageReleaseTime
: [{ version: 'x.y.z', days: 0 }]
}
margin={{ top: 5, right: 30, left: 20, bottom: 5 }}
layout="vertical"
>
<XAxis type="number" />
<YAxis dataKey="version" type="category" />
<Tooltip labelStyle={{ color: '#000', fontWeight: 'bold' }} />
<Legend />
<Bar dataKey="days" fill="#82ca9d" />
</BarChart>
{progress > 0 && progress < 100 && (
<Box marginTop={1}>
<LinearProgressWithLabel progress={progress} responseSteps={[]} />
</Box>
)}
</Box>
</Box>
);
}