Outil utilisé: Gemini (option Canvas)
Temps: moins de 5 minutes
"Peux-tu me créer une application qui me permettrait d'entrer des données pour produire un diagramme circulaire avec un bouton pour exporter le diagramme créé sous forme d'image? "
Absolument ! Je peux vous créer une application web simple et élégante pour cela.
Voici un outil qui vous permettra de saisir vos données, de générer instantanément un diagramme circulaire et de l'exporter en tant qu'image PNG. J'ai ajouté des exemples de données pour que vous puissiez commencer tout de suite.
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Créateur de Diagramme Circulaire</title>
<!-- Utilisation de Tailwind CSS pour un design moderne -->
<script src="https://cdn.tailwindcss.com"></script>
<!-- Utilisation de la bibliothèque Chart.js pour les diagrammes -->
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
<style>
body {
font-family: 'Inter', sans-serif;
}
</style>
</head>
<body class="bg-gray-100 flex items-center justify-center min-h-screen p-4">
<div class="w-full max-w-4xl bg-white rounded-xl shadow-lg p-6 md:p-8">
<div class="text-center mb-8">
<h1 class="text-3xl md:text-4xl font-bold text-gray-800">Créateur de Diagramme Circulaire</h1>
<p class="text-gray-500 mt-2">Saisissez vos données, visualisez votre diagramme et exportez-le en un clic.</p>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-8 items-start">
<!-- Section de saisie des données -->
<div class="space-y-4">
<div>
<label for="chartData" class="block text-sm font-medium text-gray-700 mb-1">
Données (Étiquette, Valeur)
</label>
<textarea id="chartData" rows="8" class="w-full p-3 border border-gray-300 rounded-lg shadow-sm focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition" placeholder="Exemple : Ventes T1, 1500 Ventes T2, 2200 Ventes T3, 1800 Ventes T4, 2500">Marketing, 120
Ventes, 250
Support Technique, 80
R&D, 150</textarea>
<p class="text-xs text-gray-500 mt-1">Entrez chaque élément sur une nouvelle ligne, séparé par une virgule.</p>
</div>
<button id="generateChartBtn" class="w-full bg-blue-600 text-white font-bold py-3 px-4 rounded-lg hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 transition-transform transform hover:scale-105">
Générer le Diagramme
</button>
<button id="exportChartBtn" class="w-full bg-green-600 text-white font-bold py-3 px-4 rounded-lg hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-green-500 transition-transform transform hover:scale-105" style="display: none;">
Exporter en PNG
</button>
<p id="errorMessage" class="text-red-500 text-sm mt-2"></p>
</div>
<!-- Section d'affichage du diagramme -->
<div class="bg-gray-50 p-4 rounded-lg h-full flex items-center justify-center min-h-[300px] md:min-h-[400px]">
<canvas id="myPieChart"></canvas>
</div>
</div>
</div>
<script>
// Références aux éléments du DOM
const dataInput = document.getElementById('chartData');
const generateBtn = document.getElementById('generateChartBtn');
const exportBtn = document.getElementById('exportChartBtn');
const errorMessage = document.getElementById('errorMessage');
const ctx = document.getElementById('myPieChart').getContext('2d');
let myPieChart = null;
// Fonction pour générer une couleur aléatoire
const getRandomColor = () => {
const r = Math.floor(Math.random() * 255);
const g = Math.floor(Math.random() * 255);
const b = Math.floor(Math.random() * 255);
return `rgba(${r}, ${g}, ${b}, 0.8)`;
};
// Fonction pour analyser les données de la zone de texte
const parseData = () => {
const rawData = dataInput.value.trim();
if (!rawData) {
errorMessage.textContent = "Veuillez entrer des données.";
return null;
}
const lines = rawData.split('\n');
const labels = [];
const values = [];
let hasError = false;
lines.forEach(line => {
const parts = line.split(',');
if (parts.length !== 2) {
hasError = true;
return;
}
const label = parts[0].trim();
const value = parseFloat(parts[1].trim());
if (label && !isNaN(value) && value >= 0) {
labels.push(label);
values.push(value);
} else {
hasError = true;
}
});
if (hasError || labels.length === 0) {
errorMessage.textContent = "Format de données invalide. Utilisez 'Étiquette, Valeur'.";
return null;
}
errorMessage.textContent = "";
return { labels, values };
};
// Fonction pour dessiner le diagramme
const drawChart = (labels, values) => {
// Détruire l'ancien diagramme s'il existe
if (myPieChart) {
myPieChart.destroy();
}
const backgroundColors = values.map(() => getRandomColor());
myPieChart = new Chart(ctx, {
type: 'pie',
data: {
labels: labels,
datasets: [{
label: 'Données',
data: values,
backgroundColor: backgroundColors,
borderColor: '#ffffff',
borderWidth: 2
}]
},
options: {
responsive: true,
maintainAspectRatio: true,
plugins: {
legend: {
position: 'top',
labels: {
font: {
size: 14
}
}
},
tooltip: {
callbacks: {
label: function(context) {
let label = context.label || '';
if (label) {
label += ': ';
}
if (context.parsed !== null) {
const total = context.chart.data.datasets[0].data.reduce((a, b) => a + b, 0);
const percentage = ((context.parsed / total) * 100).toFixed(2);
label += `${context.raw} (${percentage}%)`;
}
return label;
}
}
},
title: {
display: true,
text: 'Répartition des Données',
font: {
size: 18,
weight: 'bold'
}
}
}
}
});
// Afficher le bouton d'exportation
exportBtn.style.display = 'block';
};
// Événement pour le bouton "Générer"
generateBtn.addEventListener('click', () => {
const data = parseData();
if (data) {
drawChart(data.labels, data.values);
} else {
if (myPieChart) {
myPieChart.destroy();
myPieChart = null;
}
exportBtn.style.display = 'none';
}
});
// Événement pour le bouton "Exporter"
exportBtn.addEventListener('click', () => {
if (myPieChart) {
const link = document.createElement('a');
link.href = myPieChart.toBase64Image();
link.download = 'diagramme-circulaire.png';
link.click();
}
});
// Générer un diagramme initial au chargement de la page
window.onload = () => {
generateBtn.click();
};
</script>
</body>
</html>
"Peux-tu le rendre plus facile d'utilisation pour un élève du primaire? Entrer les donnés dans un tableau, avoir des couleurs et des images plus appropriées. "
Bien sûr ! J'ai entièrement repensé l'application pour la rendre beaucoup plus amusante et facile à utiliser pour un élève du primaire.
J'ai remplacé la zone de texte par un tableau simple où l'on peut ajouter ou supprimer des éléments, j'ai choisi une palette de couleurs vives et j'ai modifié le style pour qu'il soit plus ludique.
Voici la nouvelle version :
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Créateur de Diagramme Amusant</title>
<!-- Utilisation de Tailwind CSS pour un design moderne -->
<script src="https://cdn.tailwindcss.com"></script>
<!-- Utilisation de la bibliothèque Chart.js pour les diagrammes -->
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<!-- Police plus arrondie et amicale -->
<link href="https://fonts.googleapis.com/css2?family=Nunito:wght@400;700;800&display=swap" rel="stylesheet">
<style>
body {
font-family: 'Nunito', sans-serif;
background-color: #f0f9ff; /* Bleu ciel très clair */
}
.btn-delete {
background-color: #fecaca; /* Rouge clair */
color: #dc2626; /* Rouge foncé */
border-radius: 9999px;
width: 28px;
height: 28px;
font-weight: bold;
display: flex;
align-items: center;
justify-content: center;
border: none;
cursor: pointer;
transition: all 0.2s;
}
.btn-delete:hover {
background-color: #ef4444;
color: white;
}
</style>
</head>
<body class="flex items-center justify-center min-h-screen p-4">
<div class="w-full max-w-4xl bg-white rounded-2xl shadow-lg p-6 md:p-8 border-4 border-blue-300">
<div class="text-center mb-8">
<h1 class="text-3xl md:text-4xl font-extrabold text-blue-600">Ton Créateur de Diagramme ! 🎨</h1>
<p class="text-gray-500 mt-2 text-lg">Dis-moi ce que tu veux dessiner !</p>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-8 items-start">
<!-- Section de saisie des données -->
<div class="space-y-4">
<div class="bg-blue-50 p-4 rounded-lg">
<p class="font-bold text-gray-700 mb-2">Écris tes choses et combien il y en a :</p>
<table class="w-full">
<tbody id="dataTableBody">
<!-- Les rangées seront ajoutées ici par JavaScript -->
</tbody>
</table>
<button id="addRowBtn" class="mt-4 w-full bg-blue-200 text-blue-800 font-bold py-2 px-4 rounded-lg hover:bg-blue-300 transition">
Ajouter un élément +
</button>
</div>
<button id="generateChartBtn" class="w-full bg-yellow-400 text-yellow-900 font-bold py-3 px-4 rounded-lg hover:bg-yellow-500 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-yellow-400 transition-transform transform hover:scale-105 text-xl">
Dessine le diagramme ! ✨
</button>
<button id="exportChartBtn" class="w-full bg-pink-500 text-white font-bold py-3 px-4 rounded-lg hover:bg-pink-600 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-pink-500 transition-transform transform hover:scale-105" style="display: none;">
Télécharger l'image 🖼️
</button>
<p id="errorMessage" class="text-red-500 text-sm mt-2 font-bold text-center"></p>
</div>
<!-- Section d'affichage du diagramme -->
<div class="bg-gray-50 p-4 rounded-2xl h-full flex items-center justify-center min-h-[300px] md:min-h-[400px]">
<canvas id="myPieChart"></canvas>
</div>
</div>
</div>
<script>
const dataTableBody = document.getElementById('dataTableBody');
const generateBtn = document.getElementById('generateChartBtn');
const exportBtn = document.getElementById('exportChartBtn');
const addRowBtn = document.getElementById('addRowBtn');
const errorMessage = document.getElementById('errorMessage');
const ctx = document.getElementById('myPieChart').getContext('2d');
let myPieChart = null;
// Palette de couleurs amusantes et vives
const kidFriendlyColors = [
'#FF6384', '#36A2EB', '#FFCE56', '#4BC0C0', '#9966FF', '#FF9F40',
'#FF6384', '#36A2EB', '#FFCE56', '#4BC0C0', '#9966FF', '#FF9F40'
];
const addRow = (label = '', value = '') => {
const row = dataTableBody.insertRow();
row.innerHTML = `
<td class="p-1">
<input type="text" value="${label}" class="w-full p-2 border border-gray-300 rounded-lg" placeholder="Chose">
</td>
<td class="p-1 w-24">
<input type="number" value="${value}" class="w-full p-2 border border-gray-300 rounded-lg" placeholder="Combien">
</td>
<td class="p-1 text-right w-8">
<button class="btn-delete" onclick="deleteRow(this)">X</button>
</td>
`;
};
const deleteRow = (button) => {
const row = button.parentNode.parentNode;
row.parentNode.removeChild(row);
};
const parseData = () => {
const rows = dataTableBody.querySelectorAll('tr');
const labels = [];
const values = [];
let hasError = false;
if (rows.length === 0) {
errorMessage.textContent = "Tu dois ajouter au moins un élément !";
return null;
}
rows.forEach(row => {
const inputs = row.querySelectorAll('input');
const label = inputs[0].value.trim();
const value = parseFloat(inputs[1].value.trim());
if (label && !isNaN(value) && value > 0) {
labels.push(label);
values.push(value);
} else if (label || !isNaN(value)) {
// Ignore empty rows, but flag partially filled rows as errors
if (label || inputs[1].value.trim()) {
hasError = true;
}
}
});
if (hasError) {
errorMessage.textContent = "Oups ! Vérifie que chaque case est bien remplie.";
return null;
}
if (labels.length === 0) {
errorMessage.textContent = "N'oublie pas de remplir les cases !";
return null;
}
errorMessage.textContent = "";
return { labels, values };
};
const drawChart = (labels, values) => {
if (myPieChart) {
myPieChart.destroy();
}
const backgroundColors = values.map((_, index) => kidFriendlyColors[index % kidFriendlyColors.length]);
myPieChart = new Chart(ctx, {
type: 'pie',
data: {
labels: labels,
datasets: [{
label: 'Données',
data: values,
backgroundColor: backgroundColors,
borderColor: '#ffffff',
borderWidth: 3
}]
},
options: {
responsive: true,
maintainAspectRatio: true,
plugins: {
legend: {
position: 'bottom',
labels: {
font: {
size: 14,
weight: 'bold'
}
}
},
tooltip: {
titleFont: {
size: 16,
weight: 'bold'
},
bodyFont: {
size: 14
},
},
title: {
display: true,
text: 'Ton Super Diagramme !',
font: {
size: 20,
weight: 'bold'
},
color: '#334155'
}
}
}
});
exportBtn.style.display = 'block';
};
generateBtn.addEventListener('click', () => {
const data = parseData();
if (data) {
drawChart(data.labels, data.values);
} else {
if (myPieChart) {
myPieChart.destroy();
myPieChart = null;
}
exportBtn.style.display = 'none';
}
});
exportBtn.addEventListener('click', () => {
if (myPieChart) {
const link = document.createElement('a');
link.href = myPieChart.toBase64Image();
link.download = 'mon-super-diagramme.png';
link.click();
}
});
addRowBtn.addEventListener('click', () => addRow());
window.onload = () => {
// Ajoute des exemples pour commencer
addRow('Pommes 🍎', 5);
addRow('Bananes 🍌', 8);
addRow('Oranges 🍊', 3);
generateBtn.click();
};
</script>
</body>
</html>