observatory
This commit is contained in:
parent
1ea4f0eae0
commit
1bc512af60
@ -96,13 +96,16 @@ export async function GET(request: Request) {
|
||||
|
||||
console.log('Fetching news from FastAPI server...');
|
||||
|
||||
const response = await fetch(`${env.NEWS_API_URL}/news?limit=12`, {
|
||||
// Get limit from query params or default to 100
|
||||
const limit = url.searchParams.get('limit') || '100';
|
||||
|
||||
const response = await fetch(`${env.NEWS_API_URL}/news?limit=${limit}`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
},
|
||||
// Add timeout to prevent hanging
|
||||
signal: AbortSignal.timeout(5000)
|
||||
signal: AbortSignal.timeout(10000) // Extended timeout for larger requests
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
|
||||
@ -16,6 +16,71 @@ interface ObservatoryMapProps {
|
||||
selectedCountry: string | null;
|
||||
}
|
||||
|
||||
// Simplified map positions for common countries
|
||||
const COUNTRY_POSITIONS: Record<string, [number, number]> = {
|
||||
// Africa
|
||||
'Sudan': [0.55, 0.45],
|
||||
'Egypt': [0.57, 0.40],
|
||||
'South Africa': [0.55, 0.65],
|
||||
'Nigeria': [0.48, 0.50],
|
||||
'Kenya': [0.59, 0.52],
|
||||
'Ethiopia': [0.60, 0.47],
|
||||
'Morocco': [0.45, 0.38],
|
||||
'Algeria': [0.47, 0.40],
|
||||
'Tunisia': [0.48, 0.36],
|
||||
|
||||
// Americas
|
||||
'USA': [0.25, 0.35],
|
||||
'New York': [0.28, 0.32],
|
||||
'Canada': [0.22, 0.25],
|
||||
'Mexico': [0.20, 0.40],
|
||||
'Brazil': [0.35, 0.60],
|
||||
'Argentina': [0.32, 0.70],
|
||||
|
||||
// Europe
|
||||
'UK': [0.45, 0.25],
|
||||
'France': [0.48, 0.30],
|
||||
'Germany': [0.50, 0.28],
|
||||
'Italy': [0.52, 0.33],
|
||||
'Spain': [0.45, 0.33],
|
||||
'Ukraine': [0.57, 0.28],
|
||||
'Russia': [0.65, 0.20],
|
||||
'Poland': [0.53, 0.26],
|
||||
'Sweden': [0.52, 0.18],
|
||||
'Norway': [0.50, 0.15],
|
||||
'Finland': [0.55, 0.15],
|
||||
'Greece': [0.55, 0.35],
|
||||
'Netherlands': [0.48, 0.25],
|
||||
'Belgium': [0.47, 0.27],
|
||||
'Portugal': [0.43, 0.35],
|
||||
'Switzerland': [0.49, 0.29],
|
||||
'Austria': [0.51, 0.29],
|
||||
|
||||
// Asia
|
||||
'China': [0.75, 0.35],
|
||||
'India': [0.70, 0.40],
|
||||
'Japan': [0.85, 0.33],
|
||||
'South Korea': [0.83, 0.32],
|
||||
'Indonesia': [0.78, 0.55],
|
||||
'Thailand': [0.75, 0.45],
|
||||
'Vietnam': [0.78, 0.43],
|
||||
'Philippines': [0.82, 0.45],
|
||||
'Malaysia': [0.76, 0.50],
|
||||
'Singapore': [0.76, 0.52],
|
||||
'Pakistan': [0.67, 0.38],
|
||||
'Iran': [0.62, 0.38],
|
||||
'Iraq': [0.60, 0.38],
|
||||
'Saudi Arabia': [0.60, 0.42],
|
||||
'Turkey': [0.58, 0.35],
|
||||
'Israel': [0.58, 0.38],
|
||||
'Palestine': [0.58, 0.39],
|
||||
'Syria': [0.59, 0.37],
|
||||
'Afghanistan': [0.65, 0.38],
|
||||
|
||||
// Oceania
|
||||
'Australia': [0.80, 0.65]
|
||||
};
|
||||
|
||||
export function ObservatoryMap({
|
||||
countries,
|
||||
onCountrySelect,
|
||||
@ -70,74 +135,52 @@ export function ObservatoryMap({
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
// Draw country markers at more fixed positions
|
||||
// Calculate the top countries by news count
|
||||
const topCountries = [...countries]
|
||||
.sort((a, b) => b.count - a.count)
|
||||
.slice(0, 15);
|
||||
|
||||
// Draw country markers for all countries
|
||||
countries.forEach((country) => {
|
||||
// Position based on country name (simplified)
|
||||
let x, y;
|
||||
|
||||
// Very simple positioning logic
|
||||
switch(country.name) {
|
||||
case 'Sudan':
|
||||
x = canvas.width * 0.55;
|
||||
y = canvas.height * 0.45;
|
||||
break;
|
||||
case 'Ukraine':
|
||||
x = canvas.width * 0.65;
|
||||
y = canvas.height * 0.25;
|
||||
break;
|
||||
case 'USA':
|
||||
case 'New York':
|
||||
x = canvas.width * 0.25;
|
||||
y = canvas.height * 0.35;
|
||||
break;
|
||||
case 'UK':
|
||||
x = canvas.width * 0.45;
|
||||
y = canvas.height * 0.25;
|
||||
break;
|
||||
case 'France':
|
||||
x = canvas.width * 0.48;
|
||||
y = canvas.height * 0.30;
|
||||
break;
|
||||
case 'China':
|
||||
x = canvas.width * 0.75;
|
||||
y = canvas.height * 0.35;
|
||||
break;
|
||||
case 'Russia':
|
||||
x = canvas.width * 0.70;
|
||||
y = canvas.height * 0.20;
|
||||
break;
|
||||
case 'India':
|
||||
x = canvas.width * 0.70;
|
||||
y = canvas.height * 0.40;
|
||||
break;
|
||||
case 'Brazil':
|
||||
x = canvas.width * 0.35;
|
||||
y = canvas.height * 0.60;
|
||||
break;
|
||||
case 'Australia':
|
||||
x = canvas.width * 0.80;
|
||||
y = canvas.height * 0.65;
|
||||
break;
|
||||
default:
|
||||
// Random position for other countries
|
||||
x = 100 + Math.random() * (canvas.width - 200);
|
||||
y = 100 + Math.random() * (canvas.height - 200);
|
||||
// Use predefined positions or random for others
|
||||
if (COUNTRY_POSITIONS[country.name]) {
|
||||
const [xRatio, yRatio] = COUNTRY_POSITIONS[country.name];
|
||||
x = canvas.width * xRatio;
|
||||
y = canvas.height * yRatio;
|
||||
} else {
|
||||
// Random position for other countries
|
||||
x = 100 + Math.random() * (canvas.width - 200);
|
||||
y = 100 + Math.random() * (canvas.height - 200);
|
||||
}
|
||||
|
||||
// Size based on count (with limits)
|
||||
const isTopCountry = topCountries.includes(country);
|
||||
const size = Math.min(Math.max(3, country.count / 2), 8);
|
||||
|
||||
// Draw marker
|
||||
ctx.beginPath();
|
||||
ctx.arc(x, y, 6, 0, Math.PI * 2);
|
||||
ctx.arc(x, y, size, 0, Math.PI * 2);
|
||||
|
||||
// Simple color
|
||||
ctx.fillStyle = country.name === 'Sudan' ? '#f87171' : '#cbd5e1';
|
||||
// Color based on count and selection
|
||||
if (country.name === selectedCountry) {
|
||||
ctx.fillStyle = '#3b82f6'; // Blue when selected
|
||||
} else if (isTopCountry) {
|
||||
ctx.fillStyle = '#f87171'; // Red for top countries
|
||||
} else {
|
||||
ctx.fillStyle = '#cbd5e1'; // Gray for others
|
||||
}
|
||||
|
||||
ctx.fill();
|
||||
|
||||
// Draw country name if it's Sudan or selected
|
||||
if (country.name === 'Sudan' || country.name === selectedCountry) {
|
||||
// Draw country name if it's a top country or selected
|
||||
if (isTopCountry || country.name === selectedCountry) {
|
||||
ctx.fillStyle = '#374151';
|
||||
ctx.font = '12px system-ui, sans-serif';
|
||||
ctx.fillText(country.name, x + 10, y + 4);
|
||||
// Show count for top countries
|
||||
ctx.fillText(`${country.name} (${country.count})`, x + 10, y + 4);
|
||||
}
|
||||
|
||||
// Store coordinates for click detection
|
||||
@ -154,11 +197,12 @@ export function ObservatoryMap({
|
||||
// Check if a country marker was clicked
|
||||
for (const country of countries) {
|
||||
if (country.x && country.y) {
|
||||
const size = Math.min(Math.max(3, country.count / 2), 8);
|
||||
const distance = Math.sqrt(
|
||||
Math.pow(x - country.x, 2) + Math.pow(y - country.y, 2)
|
||||
);
|
||||
|
||||
if (distance <= 8) {
|
||||
if (distance <= size + 2) {
|
||||
onCountrySelect(country.name);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -29,7 +29,7 @@ export function ObservatoryView() {
|
||||
setLoading(true);
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/news?limit=50');
|
||||
const response = await fetch('/api/news?limit=100');
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to fetch news');
|
||||
}
|
||||
@ -57,21 +57,38 @@ export function ObservatoryView() {
|
||||
const countries = [
|
||||
'France', 'USA', 'Canada', 'UK', 'Germany', 'Japan', 'China',
|
||||
'India', 'Brazil', 'Australia', 'Russia', 'Italy', 'Spain',
|
||||
'Sudan', 'New York', 'United Nations', 'Ukraine'
|
||||
'Sudan', 'New York', 'United Nations', 'Ukraine', 'Egypt',
|
||||
'Mexico', 'South Africa', 'Nigeria', 'Argentina', 'Pakistan',
|
||||
'Indonesia', 'Saudi Arabia', 'Iran', 'Turkey', 'South Korea',
|
||||
'Thailand', 'Vietnam', 'Philippines', 'Malaysia', 'Singapore',
|
||||
'Israel', 'Palestine', 'Syria', 'Iraq', 'Afghanistan',
|
||||
'Morocco', 'Algeria', 'Tunisia', 'Kenya', 'Ethiopia',
|
||||
'Greece', 'Poland', 'Sweden', 'Norway', 'Denmark', 'Finland',
|
||||
'Netherlands', 'Belgium', 'Portugal', 'Switzerland', 'Austria'
|
||||
];
|
||||
|
||||
// Sort countries by length (to prioritize longer names)
|
||||
const sortedCountries = [...countries].sort((a, b) => b.length - a.length);
|
||||
|
||||
const result: Record<string, NewsItem[]> = {};
|
||||
|
||||
newsItems.forEach(item => {
|
||||
countries.forEach(country => {
|
||||
if (
|
||||
(item.title && item.title.includes(country)) ||
|
||||
(item.description && item.description.includes(country))
|
||||
) {
|
||||
// For title and description
|
||||
const titleAndDesc = [
|
||||
item.title || '',
|
||||
item.description || ''
|
||||
].join(' ').toLowerCase();
|
||||
|
||||
// Check each country
|
||||
sortedCountries.forEach(country => {
|
||||
if (titleAndDesc.includes(country.toLowerCase())) {
|
||||
if (!result[country]) {
|
||||
result[country] = [];
|
||||
}
|
||||
result[country].push(item);
|
||||
// Only add once per item
|
||||
if (!result[country].some(existingItem => existingItem.id === item.id)) {
|
||||
result[country].push(item);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Loading…
Reference in New Issue
Block a user