nezha_dash/app/(main)/ClientComponents/Global.tsx
2024-11-21 01:00:30 +08:00

112 lines
3.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { countryCodeMapping, reverseCountryCodeMapping } from "@/lib/geo";
import { countryCoordinates } from "@/lib/geo-limit";
import { GetNezhaData } from "@/lib/serverFetch";
import { ServerStackIcon } from "@heroicons/react/20/solid";
import * as turf from "@turf/turf";
import DottedMap from "dotted-map/without-countries";
import Link from "next/link";
import { geoJsonString } from "../../../lib/geo-json-string";
import { mapJsonString } from "../../../lib/map-string";
interface GlobalProps {
countries?: string[];
}
export default async function ServerGlobal() {
const nezhaServerList = await GetNezhaData();
const countrytList: string[] = [];
nezhaServerList.result.forEach((server) => {
if (server.host.CountryCode) {
server.host.CountryCode = server.host.CountryCode.toUpperCase();
if (!countrytList.includes(server.host.CountryCode)) {
countrytList.push(server.host.CountryCode);
}
}
});
return <Global countries={countrytList} />;
}
export async function Global({ countries = [] }: GlobalProps) {
const map = new DottedMap({ map: JSON.parse(mapJsonString) });
const countries_alpha3 = countries
.map((code) => countryCodeMapping[code])
.filter((code) => code !== undefined);
const geoJson = JSON.parse(geoJsonString);
countries_alpha3.forEach((countryCode) => {
const feature = geoJson.features.find(
(f: any) => f.properties.iso_a3 === countryCode,
);
if (feature) {
// 获取国家的边界框
const bbox = turf.bbox(feature);
const spacing = 50; // 单位为千米,值越小点越密集
const options = { units: "kilometers" };
// @ts-expect-error ignore
const pointGrid = turf.pointGrid(bbox, spacing, options);
// 过滤出位于国家多边形内部的点
const pointsWithin = turf.pointsWithinPolygon(pointGrid, feature);
// 如果没有点在多边形内部,则使用国家的中心点
if (pointsWithin.features.length === 0) {
const centroid = turf.centroid(feature);
const [lng, lat] = centroid.geometry.coordinates;
map.addPin({
lat,
lng,
svgOptions: { color: "#FF4500", radius: 0.3 },
});
} else {
pointsWithin.features.forEach((point: any) => {
const [lng, lat] = point.geometry.coordinates;
map.addPin({
lat,
lng,
svgOptions: { color: "#FF4500", radius: 0.3 },
});
});
}
} else {
// 如果找不到feature使用countryCoordinates中的坐标
const alpha2Code = reverseCountryCodeMapping[countryCode];
if (alpha2Code && countryCoordinates[alpha2Code]) {
const coordinates = countryCoordinates[alpha2Code];
map.addPin({
lat: coordinates.lat,
lng: coordinates.lng,
svgOptions: { color: "#FF4500", radius: 0.3 },
});
}
}
});
const finalMap = map.getSVG({
radius: 0.35,
color: "#D1D5DA",
shape: "circle",
});
return (
<section className="flex flex-col gap-4 mt-[3.2px]">
<Link
href={`/`}
className="rounded-[50px] w-fit bg-stone-100 p-[10px] transition-all hover:bg-stone-200 dark:hover:bg-stone-700 dark:bg-stone-800"
>
<ServerStackIcon className="size-4" />
</Link>
<img
src={`data:image/svg+xml;utf8,${encodeURIComponent(finalMap)}`}
alt="World Map with Highlighted Countries"
/>
</section>
);
}