// ── Reproducible synthetic data (seeded PRNG, no network) ──────────────
function mulberry32(a) {
return function () {
a |= 0
a = (a + 0x6d2b79f5) | 0
var t = Math.imul(a ^ (a >>> 15), 1 | a)
t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t
return ((t ^ (t >>> 14)) >>> 0) / 4294967296
}
}
var rng = mulberry32(20240607)
function gauss(mean, sd) {
var u = 0,
v = 0
while (u === 0) u = rng()
while (v === 0) v = rng()
return mean + sd * Math.sqrt(-2 * Math.log(u)) * Math.cos(2 * Math.PI * v)
}
// Individual API response-time readings per data-centre region. Compact
// strip-plot form: { x: 'Region', y: [reading, reading, ...] }. Every reading
// becomes its own hoverable marker, scattered horizontally within its band.
var REGIONS = [
{ name: 'Frankfurt', mean: 120, sd: 22 },
{ name: 'Mumbai', mean: 182, sd: 30 },
{ name: 'Oregon', mean: 96, sd: 18 },
{ name: 'Singapore', mean: 158, sd: 26 },
{ name: 'Virginia', mean: 82, sd: 16 },
]
function readings(region) {
var out = []
for (var i = 0; i < 150; i++) {
out.push(Math.max(20, Math.round(gauss(region.mean, region.sd))))
}
return out
}
var options = {
series: [
{
name: 'Frankfurt',
data: [{ x: 'Frankfurt', y: readings(REGIONS[0]) }],
},
{
name: 'Mumbai',
data: [{ x: 'Mumbai', y: readings(REGIONS[1]) }],
},
{
name: 'Oregon',
data: [{ x: 'Oregon', y: readings(REGIONS[2]) }],
},
{
name: 'Singapore',
data: [{ x: 'Singapore', y: readings(REGIONS[3]) }],
},
{
name: 'Virginia',
data: [{ x: 'Virginia', y: readings(REGIONS[4]) }],
},
],
chart: {
type: 'scatter',
height: 460,
},
title: {
text: 'API response time by region',
align: 'center',
},
plotOptions: {
scatter: {
// Spread the readings in each band horizontally (axis units; 1 = one
// band step). Set `distributed: true` to colour each band differently.
jitter: {
enabled: true,
x: 0.35,
},
},
},
markers: {
size: 3,
strokeWidth: 0,
},
fill: {
opacity: 0.6,
},
legend: { show: false },
xaxis: {
// strip plots read better without the vertical crosshair line
crosshairs: { show: false },
},
yaxis: {
title: { text: 'Response time (ms)' },
labels: {
formatter: function (v) {
return Math.round(v)
},
},
},
tooltip: {
// anchor the tooltip to the hovered band so it stays put instead of
// chasing each individual marker
shared: true,
intersect: false,
y: {
formatter: function (v) {
return Math.round(v) + ' ms'
},
},
},
}
var chart = new ApexCharts(document.querySelector('#chart'), options)
chart.render()