Files
kolaytercih/scripts/ulke-harita-uret.ts
bilalgursen ce6871d623
Some checks failed
Deploy / deploy (push) Has been cancelled
refactor: güncellenmiş profil çerezi ile sonuç sayfası yönlendirmeleri
Profil çerezinin SSR'da kullanılmasını sağlayarak, sonuç sayfasındaki yönlendirmeleri güncelledik. Artık profil bilgileri URL parametreleri yerine çerezden alınarak işleniyor. Ayrıca, profil çerezi olmayan kullanıcılar için yönlendirme mantığı iyileştirildi. Çeşitli bileşenlerdeki URL oluşturma fonksiyonları güncellenerek, profil bilgileri çerezden okunacak şekilde düzenlendi. Bu değişiklikler, kullanıcı deneyimini artırmayı ve daha tutarlı bir veri akışı sağlamayı hedefliyor.
2026-08-09 03:31:42 +03:00

210 lines
7.0 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.
// Yurtdışı üniversite sayfaları için ülke kontürlerini üretir.
//
// Kaynak: Natural Earth 10m admin_0_countries (kamu malı). GeoJSON bir kez
// indirilip tmp'ye önbelleklenir; çıktı src/lib/harita-ulkeler-verisi.ts
// dosyasına yazılır ve repo'ya commit'lenir (build ağa çıkmaz).
//
// Projeksiyon: ülke başına eşdikdörtgen (plate carrée) + cos(ortaEnlem)
// düzeltmesi; Türkiye haritasının kırpılmış oranıyla aynı 1050×447 kutuya
// sığdırılır. Nokta seyreltme ~1px eşikli olduğundan çıktı küçük kalır.
//
// Çalıştırma: pnpm tsx scripts/ulke-harita-uret.ts
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
const GENISLIK = 1050;
const YUKSEKLIK = 447;
const KENAR_PAYI = 26;
const SEYRELTME_PX = 1.1;
const MIN_HALKA_PX = 3; // bbox'u bundan küçük halkalar (adacıklar) atlanır
const KAYNAK_URL =
"https://raw.githubusercontent.com/nvkelso/natural-earth-vector/master/geojson/ne_10m_admin_0_countries.geojson";
type UlkeTanim = {
kod: string;
ad: string;
/** Vurgulanan (mavi) NE ADMIN adları */
vurgulu: string[];
/** Soluk çizilen bağlam parçaları (ör. Kıbrıs'ın güneyi) */
baglam?: string[];
};
const ULKELER: UlkeTanim[] = [
{
kod: "kktc",
ad: "KKTC",
vurgulu: ["Northern Cyprus"],
baglam: [
"Cyprus",
"Cyprus No Mans Area",
"Dhekelia Sovereign Base Area",
"Akrotiri Sovereign Base Area",
],
},
{ kod: "azerbaycan", ad: "Azerbaycan", vurgulu: ["Azerbaijan"] },
{ kod: "kirgizistan", ad: "Kırgızistan", vurgulu: ["Kyrgyzstan"] },
{ kod: "kazakistan", ad: "Kazakistan", vurgulu: ["Kazakhstan"] },
{
kod: "bosna-hersek",
ad: "Bosna-Hersek",
vurgulu: ["Bosnia and Herzegovina"],
},
{ kod: "makedonya", ad: "Kuzey Makedonya", vurgulu: ["North Macedonia"] },
{ kod: "arnavutluk", ad: "Arnavutluk", vurgulu: ["Albania"] },
];
type Halka = [number, number][]; // [lng, lat]
async function geojsonGetir(): Promise<{
features: {
properties: { ADMIN: string };
geometry: { type: string; coordinates: unknown };
}[];
}> {
const cachePath = path.join(os.tmpdir(), "ne_10m_admin_0_countries.geojson");
if (!fs.existsSync(cachePath)) {
console.log("indiriliyor:", KAYNAK_URL);
const res = await fetch(KAYNAK_URL);
if (!res.ok) throw new Error(`indirme başarısız: ${res.status}`);
fs.writeFileSync(cachePath, Buffer.from(await res.arrayBuffer()));
}
return JSON.parse(fs.readFileSync(cachePath, "utf8"));
}
function halkalar(geometry: { type: string; coordinates: unknown }): Halka[] {
if (geometry.type === "Polygon") return geometry.coordinates as Halka[];
if (geometry.type === "MultiPolygon")
return (geometry.coordinates as Halka[][]).flat();
throw new Error(`beklenmeyen geometri: ${geometry.type}`);
}
function pathUret(
ringler: Halka[],
proje: (lng: number, lat: number) => { x: number; y: number },
): string[] {
const parcalar: string[] = [];
for (const ring of ringler) {
const pts = ring.map(([lng, lat]) => proje(lng, lat));
const xs = pts.map((p) => p.x);
const ys = pts.map((p) => p.y);
if (
Math.max(...xs) - Math.min(...xs) < MIN_HALKA_PX &&
Math.max(...ys) - Math.min(...ys) < MIN_HALKA_PX
)
continue;
let d = "";
let sonX = NaN;
let sonY = NaN;
for (let i = 0; i < pts.length; i++) {
const { x, y } = pts[i];
if (i > 0 && Math.hypot(x - sonX, y - sonY) < SEYRELTME_PX) continue;
d += `${d ? "L" : "M"}${x.toFixed(1)} ${y.toFixed(1)}`;
sonX = x;
sonY = y;
}
d += "Z";
if (d.length > 10) parcalar.push(d);
}
return parcalar;
}
async function main() {
const geojson = await geojsonGetir();
const byAdmin = new Map(
geojson.features.map((f) => [f.properties.ADMIN, f] as const),
);
const cikti: string[] = [];
const kodlar = ULKELER.map((u) => `"${u.kod}"`).join(" | ");
cikti.push(
"// Bu dosya scripts/ulke-harita-uret.ts tarafından üretildi — elle düzenleme.",
"// Kaynak: Natural Earth 10m admin_0_countries (kamu malı).",
"",
`export type UlkeKodu = ${kodlar};`,
"",
"export type UlkeHarita = {",
" ad: string;",
" /** lat/lng → viewBox koordinatı: x = ax*lng + bx, y = ay*lat + by */",
" proje: { ax: number; bx: number; ay: number; by: number };",
" /** Vurgulanan ülke kontürleri */",
" ulke: string[];",
" /** Soluk çizilen bağlam kontürleri (ör. Kıbrıs adasının güneyi) */",
" baglam: string[];",
"};",
"",
`export const ULKE_HARITA_GENISLIK = ${GENISLIK};`,
`export const ULKE_HARITA_YUKSEKLIK = ${YUKSEKLIK};`,
"",
"export const ULKE_HARITALARI: Record<UlkeKodu, UlkeHarita> = {",
);
for (const ulke of ULKELER) {
const adlar = [...ulke.vurgulu, ...(ulke.baglam ?? [])];
const geometriler = adlar.map((ad) => {
const f = byAdmin.get(ad);
if (!f) throw new Error(`Natural Earth'te bulunamadı: ${ad}`);
return { ad, ringler: halkalar(f.geometry) };
});
// Sığdırma: tüm parçaların (bağlam dahil) bbox'una göre tek ölçek
const tumNoktalar = geometriler.flatMap((g) => g.ringler.flat());
const latler = tumNoktalar.map(([, lat]) => lat);
const ortaLat = (Math.min(...latler) + Math.max(...latler)) / 2;
const kx = Math.cos((ortaLat * Math.PI) / 180);
const pxler = tumNoktalar.map(([lng]) => lng * kx);
const pyler = tumNoktalar.map(([, lat]) => -lat);
const minX = Math.min(...pxler);
const maxX = Math.max(...pxler);
const minY = Math.min(...pyler);
const maxY = Math.max(...pyler);
const s = Math.min(
(GENISLIK - 2 * KENAR_PAYI) / (maxX - minX),
(YUKSEKLIK - 2 * KENAR_PAYI) / (maxY - minY),
);
const ox = (GENISLIK - s * (maxX - minX)) / 2;
const oy = (YUKSEKLIK - s * (maxY - minY)) / 2;
const proje = (lng: number, lat: number) => ({
x: s * (lng * kx - minX) + ox,
y: s * (-lat - minY) + oy,
});
const vurguluPaths = geometriler
.filter((g) => ulke.vurgulu.includes(g.ad))
.flatMap((g) => pathUret(g.ringler, proje));
const baglamPaths = geometriler
.filter((g) => !ulke.vurgulu.includes(g.ad))
.flatMap((g) => pathUret(g.ringler, proje));
const yaz = (n: number) => Number(n.toFixed(4));
cikti.push(
` "${ulke.kod}": {`,
` ad: ${JSON.stringify(ulke.ad)},`,
` proje: { ax: ${yaz(s * kx)}, bx: ${yaz(ox - s * minX)}, ay: ${yaz(-s)}, by: ${yaz(oy - s * minY)} },`,
` ulke: ${JSON.stringify(vurguluPaths)},`,
` baglam: ${JSON.stringify(baglamPaths)},`,
" },",
);
console.log(
`${ulke.kod}: ${vurguluPaths.length} vurgulu + ${baglamPaths.length} bağlam path, ` +
`~${Math.round((vurguluPaths.join("").length + baglamPaths.join("").length) / 1024)}KB`,
);
}
cikti.push("};", "");
const hedef = path.join(
process.cwd(),
"src",
"lib",
"harita-ulkeler-verisi.ts",
);
fs.writeFileSync(hedef, cikti.join("\n"));
console.log("yazıldı:", hedef);
}
main();