<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div id="controls">
<h3>Bảng Điều Khiển ????</h3>
<input type="text" id="idea-text" placeholder="Nhập ý tưởng...">
<button id="add-planet-btn">Thêm Hành Tinh (Ý tưởng chính)</button>
<p style="font-size: 12px; margin: 0; text-align: center; opacity: 0.8;"><i>*Chọn một hành tinh trước*</i></p>
<button id="add-asteroid-btn" disabled>Thêm Tiểu Hành Tinh (Ý tưởng con)</button>
</div>
<div id="mindmap-container"></div>
<script src="script.js"></script>
</body>
</html>
/* CSS cho giao diện */
:root {
--background-color: #00001a;
--text-color: #f0f0f0;
--control-panel-bg: rgba(25, 25, 55, 0.85);
--control-panel-border: #4a4a8a;
--button-bg: #4a4a8a;
--button-hover-bg: #6a6acc;
--input-bg: #1a1a3a;
--planet-shadow: rgba(255, 255, 200, 0.6);
--planet-selected-glow: #ffdd44;
--orbit-color: rgba(255, 255, 255, 0.4);
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background-color: var(--background-color);
color: var(--text-color);
margin: 0;
padding: 0;
overflow: hidden; /* Ngăn thanh cuộn xuất hiện */
display: flex;
justify-content: center;
align-items: center;
}
#mindmap-container {
position: relative;
width: 100vw;
height: 100vh;
/* Tạo hiệu ứng các vì sao lấp lánh bằng background */
background-image:
radial-gradient(1px 1px at 20px 30px, white, transparent),
radial-gradient(1px 1px at 40px 70px, white, transparent),
radial-gradient(1px 1px at 80px 120px, white, transparent),
radial-gradient(1.5px 1.5px at 150px 80px, white, transparent),
radial-gradient(1px 1px at 180px 20px, white, transparent);
background-repeat: repeat;
background-size: 200px 200px;
}
#controls {
position: fixed;
top: 20px;
left: 20px;
background: var(--control-panel-bg);
padding: 15px 20px;
border-radius: 12px;
z-index: 1000;
display: flex;
flex-direction: column;
gap: 12px;
border: 1px solid var(--control-panel-border);
backdrop-filter: blur(5px);
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.4);
}
#controls h3 {
margin: 0;
padding-bottom: 5px;
border-bottom: 1px solid var(--control-panel-border);
text-align: center;
}
#idea-text {
padding: 10px;
border-radius: 8px;
border: 1px solid var(--control-panel-border);
background-color: var(--input-bg);
color: var(--text-color);
width: 200px;
outline: none;
transition: border-color 0.3s;
}
#idea-text:focus {
border-color: var(--button-hover-bg);
}
button {
padding: 10px;
border-radius: 8px;
border: none;
background-color: var(--button-bg);
color: var(--text-color);
cursor: pointer;
font-weight: bold;
transition: background-color 0.3s, transform 0.1s;
}
button:hover {
background-color: var(--button-hover-bg);
}
button:active {
transform: scale(0.98);
}
button:disabled {
background-color: #333;
cursor: not-allowed;
opacity: 0.6;
}
.planet, .asteroid {
position: absolute;
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
text-align: center;
padding: 5px;
box-sizing: border-box;
cursor: pointer;
color: #000;
font-weight: bold;
transition: box-shadow 0.3s ease-in-out;
user-select: none; /* Ngăn chọn văn bản */
}
.planet {
width: 120px;
height: 120px;
background: radial-gradient(circle, #ffcc00, #ff6600);
box-shadow: 0 0 20px 5px var(--planet-shadow);
z-index: 10;
font-size: 16px;
}
.asteroid {
width: 60px;
height: 60px;
background: radial-gradient(circle, #c0c0c0, #808080);
box-shadow: 0 0 10px rgba(200, 200, 200, 0.5);
z-index: 20;
font-size: 12px;
}
.planet.selected {
box-shadow: 0 0 30px 10px var(--planet-selected-glow);
}
.orbit {
position: absolute;
border: 1px dashed var(--orbit-color);
border-radius: 50%; /* Sẽ thành elip vì width != height */
pointer-events: none; /* Cho phép click xuyên qua quỹ đạo */
z-index: 5;
}
document.addEventListener('DOMContentLoaded', () => {
// --- Lấy các phần tử DOM cần thiết ---
const container = document.getElementById('mindmap-container');
const ideaText = document.getElementById('idea-text');
const addPlanetBtn = document.getElementById('add-planet-btn');
const addAsteroidBtn = document.getElementById('add-asteroid-btn');
let selectedPlanet = null; // Lưu trữ hành tinh đang được chọn
// --- Hàm tạo một hành tinh mới ---
function createPlanet(text) {
const planet = document.createElement('div');
planet.className = 'planet';
planet.textContent = text;
planet.dataset.asteroids = 0; // Dùng để đếm số tiểu hành tinh của hành tinh này
// Đặt hành tinh ở một vị trí ngẫu nhiên, tránh các cạnh màn hình
const containerRect = container.getBoundingClientRect();
const planetSize = 120;
const x = Math.random() * (containerRect.width - planetSize * 2) + planetSize;
const y = Math.random() * (containerRect.height - planetSize * 2) + planetSize;
planet.style.left = `${x}px`;
planet.style.top = `${y}px`;
// Sự kiện khi click vào hành tinh
planet.addEventListener('click', (e) => {
e.stopPropagation(); // Ngăn sự kiện click lan ra container
selectPlanet(planet);
});
container.appendChild(planet);
return planet;
}
// --- Hàm tạo một tiểu hành tinh mới ---
function createAsteroid(text, parentPlanet) {
const asteroid = document.createElement('div');
asteroid.className = 'asteroid';
asteroid.textContent = text;
container.appendChild(asteroid);
// Tăng số lượng tiểu hành tinh của hành tinh mẹ
const numAsteroids = parseInt(parentPlanet.dataset.asteroids) + 1;
parentPlanet.dataset.asteroids = numAsteroids;
// --- Thiết lập quỹ đạo Elip ---
const parentRect = parentPlanet.getBoundingClientRect();
const parentCenterX = parentRect.left + parentRect.width / 2;
const parentCenterY = parentRect.top + parentRect.height / 2;
// Bán kính trục x và y của elip, tăng dần cho mỗi tiểu hành tinh mới
const rx = 100 + numAsteroids * 45;
const ry = 70 + numAsteroids * 30;
const angleOffset = Math.random() * Math.PI * 2; // Góc bắt đầu ngẫu nhiên để chúng không bị xếp chồng
const speed = (0.005 + Math.random() * 0.005) * (Math.random() > 0.5 ? 1 : -1); // Tốc độ và hướng quay ngẫu nhiên
// Vẽ quỹ đạo (một div hình elip)
const orbit = document.createElement('div');
orbit.className = 'orbit';
orbit.style.width = `${rx * 2}px`;
orbit.style.height = `${ry * 2}px`;
orbit.style.left = `${parentCenterX - rx}px`;
orbit.style.top = `${parentCenterY - ry}px`;
container.appendChild(orbit);
// --- Animation cho tiểu hành tinh ---
let angle = 0;
function animate() {
angle += speed;
// Công thức tính tọa độ trên một elip
const x = parentCenterX + rx * Math.cos(angle + angleOffset) - asteroid.offsetWidth / 2;
const y = parentCenterY + ry * Math.sin(angle + angleOffset) - asteroid.offsetHeight / 2;
asteroid.style.left = `${x}px`;
asteroid.style.top = `${y}px`;
requestAnimationFrame(animate); // Lặp lại animation cho khung hình tiếp theo
}
animate(); // Bắt đầu animation
}
// --- Hàm quản lý việc chọn hành tinh ---
function selectPlanet(planet) {
// Bỏ chọn hành tinh cũ (nếu có)
if (selectedPlanet) {
selectedPlanet.classList.remove('selected');
}
// Chọn hành tinh mới và làm nó phát sáng
selectedPlanet = planet;
selectedPlanet.classList.add('selected');
addAsteroidBtn.disabled = false; // Kích hoạt nút thêm tiểu hành tinh
}
// --- Hàm bỏ chọn tất cả ---
function deselectAll() {
if (selectedPlanet) {
selectedPlanet.classList.remove('selected');
}
selectedPlanet = null;
addAsteroidBtn.disabled = true; // Vô hiệu hóa lại nút
}
// --- Gán sự kiện cho các nút điều khiển ---
addPlanetBtn.addEventListener('click', () => {
const text = ideaText.value.trim();
if (text) {
createPlanet(text);
ideaText.value = '';
ideaText.focus();
} else {
alert('Vui lòng nhập tên cho hành tinh!');
}
});
addAsteroidBtn.addEventListener('click', () => {
const text = ideaText.value.trim();
if (text && selectedPlanet) {
createAsteroid(text, selectedPlanet);
ideaText.value = '';
ideaText.focus();
} else if (!text) {
alert('Vui lòng nhập tên cho tiểu hành tinh!');
}
});
// Cho phép nhấn Enter để thêm
ideaText.addEventListener('keyup', (e) => {
if (e.key === 'Enter') {
if (selectedPlanet && !addAsteroidBtn.disabled) {
addAsteroidBtn.click();
} else {
addPlanetBtn.click();
}
}
});
// Bỏ chọn khi click ra nền không gian
container.addEventListener('click', deselectAll);
});