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...');
|
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',
|
method: 'GET',
|
||||||
headers: {
|
headers: {
|
||||||
'Accept': 'application/json',
|
'Accept': 'application/json',
|
||||||
},
|
},
|
||||||
// Add timeout to prevent hanging
|
// Add timeout to prevent hanging
|
||||||
signal: AbortSignal.timeout(5000)
|
signal: AbortSignal.timeout(10000) // Extended timeout for larger requests
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
|
|||||||
@ -16,6 +16,71 @@ interface ObservatoryMapProps {
|
|||||||
selectedCountry: string | null;
|
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({
|
export function ObservatoryMap({
|
||||||
countries,
|
countries,
|
||||||
onCountrySelect,
|
onCountrySelect,
|
||||||
@ -70,74 +135,52 @@ export function ObservatoryMap({
|
|||||||
ctx.stroke();
|
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) => {
|
countries.forEach((country) => {
|
||||||
// Position based on country name (simplified)
|
// Position based on country name (simplified)
|
||||||
let x, y;
|
let x, y;
|
||||||
|
|
||||||
// Very simple positioning logic
|
// Use predefined positions or random for others
|
||||||
switch(country.name) {
|
if (COUNTRY_POSITIONS[country.name]) {
|
||||||
case 'Sudan':
|
const [xRatio, yRatio] = COUNTRY_POSITIONS[country.name];
|
||||||
x = canvas.width * 0.55;
|
x = canvas.width * xRatio;
|
||||||
y = canvas.height * 0.45;
|
y = canvas.height * yRatio;
|
||||||
break;
|
} else {
|
||||||
case 'Ukraine':
|
// Random position for other countries
|
||||||
x = canvas.width * 0.65;
|
x = 100 + Math.random() * (canvas.width - 200);
|
||||||
y = canvas.height * 0.25;
|
y = 100 + Math.random() * (canvas.height - 200);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Size based on count (with limits)
|
||||||
|
const isTopCountry = topCountries.includes(country);
|
||||||
|
const size = Math.min(Math.max(3, country.count / 2), 8);
|
||||||
|
|
||||||
// Draw marker
|
// Draw marker
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
ctx.arc(x, y, 6, 0, Math.PI * 2);
|
ctx.arc(x, y, size, 0, Math.PI * 2);
|
||||||
|
|
||||||
// Simple color
|
// Color based on count and selection
|
||||||
ctx.fillStyle = country.name === 'Sudan' ? '#f87171' : '#cbd5e1';
|
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();
|
ctx.fill();
|
||||||
|
|
||||||
// Draw country name if it's Sudan or selected
|
// Draw country name if it's a top country or selected
|
||||||
if (country.name === 'Sudan' || country.name === selectedCountry) {
|
if (isTopCountry || country.name === selectedCountry) {
|
||||||
ctx.fillStyle = '#374151';
|
ctx.fillStyle = '#374151';
|
||||||
ctx.font = '12px system-ui, sans-serif';
|
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
|
// Store coordinates for click detection
|
||||||
@ -154,11 +197,12 @@ export function ObservatoryMap({
|
|||||||
// Check if a country marker was clicked
|
// Check if a country marker was clicked
|
||||||
for (const country of countries) {
|
for (const country of countries) {
|
||||||
if (country.x && country.y) {
|
if (country.x && country.y) {
|
||||||
|
const size = Math.min(Math.max(3, country.count / 2), 8);
|
||||||
const distance = Math.sqrt(
|
const distance = Math.sqrt(
|
||||||
Math.pow(x - country.x, 2) + Math.pow(y - country.y, 2)
|
Math.pow(x - country.x, 2) + Math.pow(y - country.y, 2)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (distance <= 8) {
|
if (distance <= size + 2) {
|
||||||
onCountrySelect(country.name);
|
onCountrySelect(country.name);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -29,7 +29,7 @@ export function ObservatoryView() {
|
|||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch('/api/news?limit=50');
|
const response = await fetch('/api/news?limit=100');
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error('Failed to fetch news');
|
throw new Error('Failed to fetch news');
|
||||||
}
|
}
|
||||||
@ -57,21 +57,38 @@ export function ObservatoryView() {
|
|||||||
const countries = [
|
const countries = [
|
||||||
'France', 'USA', 'Canada', 'UK', 'Germany', 'Japan', 'China',
|
'France', 'USA', 'Canada', 'UK', 'Germany', 'Japan', 'China',
|
||||||
'India', 'Brazil', 'Australia', 'Russia', 'Italy', 'Spain',
|
'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[]> = {};
|
const result: Record<string, NewsItem[]> = {};
|
||||||
|
|
||||||
newsItems.forEach(item => {
|
newsItems.forEach(item => {
|
||||||
countries.forEach(country => {
|
// For title and description
|
||||||
if (
|
const titleAndDesc = [
|
||||||
(item.title && item.title.includes(country)) ||
|
item.title || '',
|
||||||
(item.description && item.description.includes(country))
|
item.description || ''
|
||||||
) {
|
].join(' ').toLowerCase();
|
||||||
|
|
||||||
|
// Check each country
|
||||||
|
sortedCountries.forEach(country => {
|
||||||
|
if (titleAndDesc.includes(country.toLowerCase())) {
|
||||||
if (!result[country]) {
|
if (!result[country]) {
|
||||||
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