document.addEventListener('DOMContentLoaded', function() { const searchButton = document.getElementById('searchButton'); const searchQuery = document.getElementById('searchQuery'); const databaseCheckboxes = document.querySelectorAll('input[name="database"]'); let timeRange, sortBy; function getSelectedFilters() { timeRange = document.querySelector('input[name="timeRange"]:checked').value; sortBy = document.querySelector('input[name="sortBy"]:checked').value; } const loadingSpinner = document.getElementById('loadingSpinner'); const resultsContainer = document.getElementById('resultsContainer'); const noResults = document.getElementById('noResults'); const resultCount = document.getElementById('resultCount'); const articleList = document.getElementById('articleList'); const constellation = d3.select('#constellation'); const tooltip = document.getElementById('tooltip'); // Search function searchButton.addEventListener('click', performSearch); searchQuery.addEventListener('keypress', function(e) { if (e.key === 'Enter') performSearch(); }); function performSearch() { const query = searchQuery.value.trim(); if (!query) return; getSelectedFilters(); showLoading(true); simulateAPICall(query); } function showLoading(show) { loadingSpinner.classList.toggle('hidden', !show); resultsContainer.classList.add('hidden'); noResults.classList.add('hidden'); } function simulateAPICall(query) { // In a real implementation, this would call actual APIs setTimeout(() => { try { // Always generate results for debugging const mockData = generateMockData(query); console.log("Generated mock data:", mockData); // Force display results even with empty query for testing if (mockData.length > 0) { displayResults(mockData); } else { // If no mock data, still show something for testing const fallbackData = generateMockData("médecine"); displayResults(fallbackData); } } catch (error) { console.error("Error displaying results:", error); // Show fallback results instead of no results const fallbackData = generateMockData("médecine"); displayResults(fallbackData); } finally { showLoading(false); } }, 500); } function generateMockData(query) { const yearsFilter = timeRange; const count = 15 + Math.floor(Math.random() * 20); const currentYear = new Date().getFullYear(); const articles = []; const centralArticleCitations = 200 + Math.floor(Math.random() * 300); // Generate central article articles.push({ title: `L'étude la plus influente sur ${query} ces dernières années`, authors: "Dupont, J.; Martin, A.; Leroy, K. et al.", journal: "Nature Medicine", year: currentYear - Math.floor(Math.random() * (yearsFilter === 'all' ? 20 : parseInt(yearsFilter))), citations: centralArticleCitations, doi: "10.1038/nm.1234", abstract: `Cette étude révolutionnaire a transformé notre compréhension de ${query} en démontrant des améliorations significatives des résultats pour les patients. L'équipe de recherche a employé des méthodologies innovantes qui sont depuis devenues standard dans le domaine.` }); // Generate surrounding articles for (let i = 0; i < count - 1; i++) { const citationCount = Math.floor(Math.random() * centralArticleCitations * 0.8); articles.push({ title: `Étude ${i+1} sur ${query}: ${['Nouvelle', 'Complète', 'Systématique', 'Randomisée', 'Clinique'][i%5]} ${['découverte', 'analyse', 'étude', 'revue', 'évaluation'][i%5]}`, authors: `${['Dubois', 'Bernard', 'Petit', 'Moreau', 'Lefevre'][i%5]}, ${String.fromCharCode(65 + (i%26))}. et al.`, journal: ["La Presse Médicale", "NEJM", "The Lancet", "BMJ", "Annales"][i%5], year: currentYear - Math.floor(Math.random() * (yearsFilter === 'all' ? 20 : parseInt(yearsFilter))), citations: citationCount, doi: `10.1234/abcd.${1000 + i}`, abstract: `Cette étude ${['importante', 'fondamentale', 'innovante', 'détaillée', 'approfondie'][i%5]} a examiné ${query} à travers l'analyse ${['clinique', 'épidémiologique', 'moléculaire', 'biochimique', 'génomique'][i%5]}. Les résultats ont ${['confirmé', 'remis en question', 'élargi', 'affiné', 'redéfini'][i%5]} les connaissances précédentes dans ce domaine.` }); } return articles; } function displayResults(articles) { // Sort articles by citations articles.sort((a, b) => b.citations - a.citations); // Update result count resultCount.textContent = `${articles.length} articles de recherche trouvés`; // Create constellation visualization createConstellation(articles); // Create article list renderArticleList(articles); // Show results resultsContainer.classList.remove('hidden'); } function createConstellation(articles) { const width = constellation.node().clientWidth; const height = constellation.node().clientHeight; const center = { x: width / 2, y: height / 2 }; // Clear previous visualization constellation.selectAll("*").remove(); // Create simulation const simulation = d3.forceSimulation() .force("link", d3.forceLink().id(d => d.id).distance(100)) .force("charge", d3.forceManyBody().strength(-100)) .force("x", d3.forceX(center.x).strength(0.1)) .force("y", d3.forceY(center.y).strength(0.1)); // Prepare nodes data const nodes = articles.map((article, i) => ({ id: i, ...article, r: Math.sqrt(article.citations) / 3, isCentral: i === 0 })); // Create links (central node connects to all others) const links = nodes.slice(1).map(node => ({ source: 0, target: node.id, value: node.citations / nodes[0].citations })); // Draw links const link = constellation.append("g") .selectAll("line") .data(links) .enter().append("line") .attr("class", "link") .attr("stroke-width", d => Math.sqrt(d.value) * 2); // Draw nodes const node = constellation.append("g") .selectAll("circle") .data(nodes) .enter().append("circle") .attr("class", d => `node ${d.isCentral ? 'central-node' : ''}`) .attr("r", d => d.r) .attr("fill", d => d.isCentral ? "#7c3aed" : "#4f46e5") .on("mouseover", showTooltip) .on("mouseout", hideTooltip) .call(d3.drag() .on("start", dragstarted) .on("drag", dragged) .on("end", dragended)); // Add node labels (central node only) constellation.append("g") .selectAll("text") .data(nodes.filter(d => d.isCentral)) .enter().append("text") .attr("dy", 4) .attr("text-anchor", "middle") .style("fill", "white") .style("font-size", "10px") .style("font-weight", "bold") .text("★"); // Update simulation simulation.nodes(nodes).on("tick", ticked); simulation.force("link").links(links); function ticked() { link .attr("x1", d => d.source.x) .attr("y1", d => d.source.y) .attr("x2", d => d.target.x) .attr("y2", d => d.target.y); node .attr("cx", d => d.x) .attr("cy", d => d.y); } function dragstarted(event, d) { if (!event.active) simulation.alphaTarget(0.3).restart(); d.fx = d.x; d.fy = d.y; } function dragged(event, d) { d.fx = event.x; d.fy = event.y; } function dragended(event, d) { if (!event.active) simulation.alphaTarget(0); d.fx = null; d.fy = null; } } function showTooltip(event, d) { tooltip.innerHTML = `

${d.title}

${d.authors}

${d.journal}, ${d.year} (Cited ${d.citations} times)

${d.abstract}

`; tooltip.style.left = `${event.pageX + 10}px`; tooltip.style.top = `${event.pageY + 10}px`; tooltip.classList.remove('hidden'); } function hideTooltip() { tooltip.classList.add('hidden'); } function renderArticleList(articles) { articleList.innerHTML = ''; articles.forEach((article, index) => { const articleElement = document.createElement('div'); articleElement.className = 'article-card bg-white rounded-lg shadow p-6'; articleElement.innerHTML = `
${index + 1}

${article.title}

${article.authors}

${article.journal}, ${article.year} · Cited ${article.citations} times

${article.abstract}

Voir la publication ${index === 0 ? ` Plus cité ` : ''}
`; articleList.appendChild(articleElement); }); } function showNoResults() { showLoading(false); resultsContainer.classList.add('hidden'); noResults.classList.remove('hidden'); // Generate fallback suggestions const suggestions = generateSearchSuggestions("médecine"); noResults.innerHTML = `

Aucun résultat trouvé

Essayez ces recherches alternatives :

${suggestions.map(s => ` `).join('')}
`; feather.replace(); } function generateSearchSuggestions(query) { const commonTerms = { 'cancer': ['cancer du sein', 'cancer du poumon', 'traitement du cancer', 'thérapie ciblée cancer'], 'diabète': ['diabète type 1', 'diabète type 2', 'traitement diabète', 'prévention diabète'], 'covid': ['covid-19', 'vaccin covid', 'variants covid', 'traitement covid'] }; // Check if query matches any common term for (const [term, suggestions] of Object.entries(commonTerms)) { if (query.toLowerCase().includes(term)) { return suggestions; } } // Default suggestions return [ query + ' traitement', query + ' étude clinique', 'nouveautés ' + query, 'méta-analyse ' + query ]; } });