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 (
);
}
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) => (
))}
);
}