update viewers page
This commit is contained in:
+58
-48
@@ -2012,32 +2012,33 @@ const shortDateFormat = new Intl.DateTimeFormat('en-GB', {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const timezoneMapPoints = {
|
const timezoneMapPoints = {
|
||||||
'America/Los_Angeles': [18, 42],
|
'America/Los_Angeles': [34.05, -118.24],
|
||||||
'America/Denver': [24, 43],
|
'America/Denver': [39.74, -104.99],
|
||||||
'America/Chicago': [30, 45],
|
'America/Chicago': [41.88, -87.63],
|
||||||
'America/New_York': [37, 43],
|
'America/New_York': [40.71, -74.01],
|
||||||
'America/Toronto': [38, 40],
|
'America/Toronto': [43.65, -79.38],
|
||||||
'America/Sao_Paulo': [43, 68],
|
'America/Phoenix': [33.45, -112.07],
|
||||||
'America/Mexico_City': [27, 54],
|
'America/Sao_Paulo': [-23.55, -46.63],
|
||||||
'Europe/London': [48, 36],
|
'America/Mexico_City': [19.43, -99.13],
|
||||||
'Europe/Paris': [51, 39],
|
'Europe/London': [51.51, -0.13],
|
||||||
'Europe/Berlin': [53, 37],
|
'Europe/Paris': [48.86, 2.35],
|
||||||
'Europe/Madrid': [49, 42],
|
'Europe/Berlin': [52.52, 13.41],
|
||||||
'Europe/Rome': [53, 43],
|
'Europe/Madrid': [40.42, -3.7],
|
||||||
'Europe/Amsterdam': [51, 37],
|
'Europe/Rome': [41.9, 12.5],
|
||||||
'Europe/Stockholm': [54, 31],
|
'Europe/Amsterdam': [52.37, 4.9],
|
||||||
'Europe/Warsaw': [56, 37],
|
'Europe/Stockholm': [59.33, 18.07],
|
||||||
'Europe/Moscow': [63, 34],
|
'Europe/Warsaw': [52.23, 21.01],
|
||||||
'Africa/Cairo': [58, 49],
|
'Europe/Moscow': [55.76, 37.62],
|
||||||
'Africa/Johannesburg': [58, 75],
|
'Africa/Cairo': [30.04, 31.24],
|
||||||
'Asia/Dubai': [66, 52],
|
'Africa/Johannesburg': [-26.2, 28.04],
|
||||||
'Asia/Kolkata': [72, 56],
|
'Asia/Dubai': [25.2, 55.27],
|
||||||
'Asia/Singapore': [79, 66],
|
'Asia/Kolkata': [22.57, 88.36],
|
||||||
'Asia/Tokyo': [88, 45],
|
'Asia/Singapore': [1.35, 103.82],
|
||||||
'Asia/Seoul': [85, 44],
|
'Asia/Tokyo': [35.68, 139.65],
|
||||||
'Asia/Shanghai': [81, 48],
|
'Asia/Seoul': [37.57, 126.98],
|
||||||
'Australia/Sydney': [90, 78],
|
'Asia/Shanghai': [31.23, 121.47],
|
||||||
'Pacific/Auckland': [95, 84],
|
'Australia/Sydney': [-33.87, 151.21],
|
||||||
|
'Pacific/Auckland': [-36.85, 174.76],
|
||||||
}
|
}
|
||||||
|
|
||||||
const countryNames = {
|
const countryNames = {
|
||||||
@@ -2092,22 +2093,15 @@ const countryMapPoints = {
|
|||||||
ZA: [24, -29],
|
ZA: [24, -29],
|
||||||
}
|
}
|
||||||
|
|
||||||
function mapPointFromPercent(x, y) {
|
|
||||||
return [
|
|
||||||
85 - (y / 100) * 145,
|
|
||||||
(x / 100) * 360 - 180,
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
function timezonePoint(timezone = '') {
|
function timezonePoint(timezone = '') {
|
||||||
if (timezoneMapPoints[timezone]) return timezoneMapPoints[timezone]
|
if (timezoneMapPoints[timezone]) return timezoneMapPoints[timezone]
|
||||||
if (timezone.startsWith('America/')) return [30, 48]
|
if (timezone.startsWith('America/')) return [39, -96]
|
||||||
if (timezone.startsWith('Europe/')) return [53, 38]
|
if (timezone.startsWith('Europe/')) return [50, 10]
|
||||||
if (timezone.startsWith('Africa/')) return [56, 60]
|
if (timezone.startsWith('Africa/')) return [0, 20]
|
||||||
if (timezone.startsWith('Asia/')) return [75, 52]
|
if (timezone.startsWith('Asia/')) return [34, 100]
|
||||||
if (timezone.startsWith('Australia/')) return [88, 76]
|
if (timezone.startsWith('Australia/')) return [-25, 134]
|
||||||
if (timezone.startsWith('Pacific/')) return [92, 70]
|
if (timezone.startsWith('Pacific/')) return [-15, 170]
|
||||||
return [50, 50]
|
return [20, 0]
|
||||||
}
|
}
|
||||||
|
|
||||||
function filledLast30Days(rows) {
|
function filledLast30Days(rows) {
|
||||||
@@ -2128,6 +2122,7 @@ function filledLast30Days(rows) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function MiniLineChart({ accent = 'text-fury-cyan', data, label, metric, stroke = '#e82517' }) {
|
function MiniLineChart({ accent = 'text-fury-cyan', data, label, metric, stroke = '#e82517' }) {
|
||||||
|
const [hoveredPoint, setHoveredPoint] = useState(null)
|
||||||
const width = 320
|
const width = 320
|
||||||
const height = 112
|
const height = 112
|
||||||
const padding = 12
|
const padding = 12
|
||||||
@@ -2143,7 +2138,7 @@ function MiniLineChart({ accent = 'text-fury-cyan', data, label, metric, stroke
|
|||||||
const latest = points.at(-1)?.value || 0
|
const latest = points.at(-1)?.value || 0
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="rounded-md border border-border bg-bg p-3">
|
<div className="relative rounded-md border border-border bg-bg p-3">
|
||||||
<div className="flex items-start justify-between gap-3">
|
<div className="flex items-start justify-between gap-3">
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm font-semibold">{label}</p>
|
<p className="text-sm font-semibold">{label}</p>
|
||||||
@@ -2161,15 +2156,31 @@ function MiniLineChart({ accent = 'text-fury-cyan', data, label, metric, stroke
|
|||||||
cy={point.y}
|
cy={point.y}
|
||||||
fill={stroke}
|
fill={stroke}
|
||||||
key={`${metric}-${point.date}`}
|
key={`${metric}-${point.date}`}
|
||||||
|
onBlur={() => setHoveredPoint(null)}
|
||||||
|
onFocus={() => setHoveredPoint(point)}
|
||||||
|
onMouseEnter={() => setHoveredPoint(point)}
|
||||||
|
onMouseLeave={() => setHoveredPoint(null)}
|
||||||
r="4"
|
r="4"
|
||||||
tabIndex="0"
|
tabIndex="0"
|
||||||
>
|
/>
|
||||||
<title>
|
|
||||||
{`${shortDateFormat.format(new Date(point.date))}: ${formatNumber(point.value)} ${label.toLowerCase()}, ${formatNumber(point.visitors || 0)} visitors`}
|
|
||||||
</title>
|
|
||||||
</circle>
|
|
||||||
))}
|
))}
|
||||||
</svg>
|
</svg>
|
||||||
|
|
||||||
|
{hoveredPoint ? (
|
||||||
|
<div
|
||||||
|
className="pointer-events-none absolute z-20 w-max max-w-52 rounded-md bg-text px-2 py-1 text-xs font-semibold text-bg shadow-lg"
|
||||||
|
style={{
|
||||||
|
left: `${(hoveredPoint.x / width) * 100}%`,
|
||||||
|
top: `${52 + (hoveredPoint.y / height) * 112}px`,
|
||||||
|
transform: 'translate(-50%, -115%)',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{shortDateFormat.format(new Date(hoveredPoint.date))}: {formatNumber(hoveredPoint.value)} {label.toLowerCase()}
|
||||||
|
<span className="block font-normal text-bg/80">
|
||||||
|
{formatNumber(hoveredPoint.visitors || 0)} visitors
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -2543,8 +2554,7 @@ function LocationSignalMap({ countries, locations }) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
fallbackLocations.forEach((location) => {
|
fallbackLocations.forEach((location) => {
|
||||||
const [x, y] = timezonePoint(location.timezone)
|
const [lat, lon] = timezonePoint(location.timezone)
|
||||||
const [lat, lon] = mapPointFromPercent(x, y)
|
|
||||||
const radius = 7 + (Number(location.visitors || 0) / maxLocationVisitors) * 16
|
const radius = 7 + (Number(location.visitors || 0) / maxLocationVisitors) * 16
|
||||||
L.circleMarker([lat, lon], {
|
L.circleMarker([lat, lon], {
|
||||||
color: '#000000',
|
color: '#000000',
|
||||||
|
|||||||
Reference in New Issue
Block a user