import React from "react"; import classNames from "classnames"; import { PingRollupInfo, PingStatus, useSolanaPingInfo, } from "providers/stats/SolanaPingProvider"; import { Bar } from "react-chartjs-2"; import { ChartOptions, ChartTooltipModel } from "chart.js"; import { Cluster, useCluster } from "providers/cluster"; export function SolanaPingCard() { const { cluster } = useCluster(); if (cluster === Cluster.Custom) { return null; } return (

Solana Ping Stats

); } function PingBarBody() { const pingInfo = useSolanaPingInfo(); if (pingInfo.status !== PingStatus.Ready) { return ( ); } return ; } type StatsNotReadyProps = { error: boolean; retry?: Function }; function StatsNotReady({ error, retry }: StatsNotReadyProps) { if (error) { return (
There was a problem loading solana ping stats.{" "} {retry && ( )}
); } return (
Loading
); } type Series = "short" | "medium" | "long"; const SERIES: Series[] = ["short", "medium", "long"]; const SERIES_INFO = { short: { label: (index: number) => index, interval: "30m", }, medium: { label: (index: number) => index * 4, interval: "2h", }, long: { label: (index: number) => index * 12, interval: "6h", }, }; const CUSTOM_TOOLTIP = function (this: any, tooltipModel: ChartTooltipModel) { // Tooltip Element let tooltipEl = document.getElementById("chartjs-tooltip"); // Create element on first render if (!tooltipEl) { tooltipEl = document.createElement("div"); tooltipEl.id = "chartjs-tooltip"; tooltipEl.innerHTML = `
`; document.body.appendChild(tooltipEl); } // Hide if no tooltip if (tooltipModel.opacity === 0) { tooltipEl.style.opacity = "0"; return; } // Set Text if (tooltipModel.body) { const { label, value } = tooltipModel.dataPoints[0]; const tooltipContent = tooltipEl.querySelector("div"); if (tooltipContent) { let innerHtml = `
${value} ms
`; innerHtml += `
${label}
`; tooltipContent.innerHTML = innerHtml; } } // Enable tooltip and set position const canvas: Element = this._chart.canvas; const position = canvas.getBoundingClientRect(); tooltipEl.style.opacity = "1"; tooltipEl.style.left = position.left + window.pageXOffset + tooltipModel.caretX + "px"; tooltipEl.style.top = position.top + window.pageYOffset + tooltipModel.caretY + "px"; }; const CHART_OPTION: ChartOptions = { tooltips: { intersect: false, // Show tooltip when cursor in between bars enabled: false, // Hide default tooltip custom: CUSTOM_TOOLTIP, }, legend: { display: false, }, scales: { xAxes: [ { ticks: { display: false, }, gridLines: { display: false, }, }, ], yAxes: [ { ticks: { stepSize: 100, fontSize: 10, fontColor: "#EEE", beginAtZero: true, display: true, }, gridLines: { display: false, }, }, ], }, animation: { duration: 0, // general animation time }, hover: { animationDuration: 0, // duration of animations when hovering an item }, responsiveAnimationDuration: 0, // animation duration after a resize }; function PingBarChart({ pingInfo }: { pingInfo: PingRollupInfo }) { const [series, setSeries] = React.useState("short"); const seriesData = pingInfo[series] || []; const seriesLength = seriesData.length; const chartData: Chart.ChartData = { labels: seriesData.map((val, i) => { return `

${val.confirmed} of ${val.submitted} confirmed

${ val.loss ? `

${val.loss.toLocaleString(undefined, { style: "percent", minimumFractionDigits: 2, })} loss

` : "" } ${SERIES_INFO[series].label(seriesLength - i)}min ago `; }), datasets: [ { backgroundColor: seriesData.map((val) => val.loss ? "#fa62fc" : "#00D192" ), hoverBackgroundColor: seriesData.map((val) => val.loss ? "#fa62fc" : "#00D192" ), borderWidth: 0, data: seriesData.map((val) => val.mean || 0), }, ], }; return (
Average Confirmation Time
{SERIES.map((key) => ( ))}
); }