|
|
# 动态球型标签云实现
我将为您创建一个动态的球型标签云,标签会围绕球体表面旋转,并具有交互效果。
## 实现思路
1. 使用CSS 3D变换创建球体结构
2. 使用JavaScript计算标签在球体表面的位置
3. 添加鼠标交互效果,使球体随鼠标移动旋转
4. 实现标签的随机颜色和悬停效果
下面是完整的实现代码:
```html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>动态球型标签云</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
background: linear-gradient(135deg, #1a2a6c, #b21f1f, #fdbb2d);
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
overflow: hidden;
}
.container {
position: relative;
width: 100%;
max-width: 1200px;
display: flex;
justify-content: center;
align-items: center;
flex-wrap: wrap;
padding: 20px;
}
h1 {
width: 100%;
text-align: center;
color: white;
margin-bottom: 30px;
text-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
font-size: 2.5rem;
}
.sphere-container {
position: relative;
width: 400px;
height: 400px;
perspective: 1000px;
}
.sphere {
position: relative;
width: 100%;
height: 100%;
transform-style: preserve-3d;
transition: transform 0.1s ease-out;
}
.tag {
position: absolute;
top: 50%;
left: 50%;
padding: 8px 16px;
border-radius: 20px;
font-weight: bold;
cursor: pointer;
transition: all 0.3s ease;
box-shadow: 0 3px 10px rgba(0, 0, 0, 0.2);
backface-visibility: hidden;
transform-origin: 0 0;
text-align: center;
user-select: none;
}
.tag:hover {
transform: scale(1.5) !important;
z-index: 10;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.4);
}
.controls {
margin-left: 50px;
background: rgba(255, 255, 255, 0.1);
padding: 20px;
border-radius: 15px;
backdrop-filter: blur(5px);
color: white;
max-width: 300px;
}
.controls h2 {
margin-bottom: 20px;
text-align: center;
}
.control-group {
margin-bottom: 15px;
}
label {
display: block;
margin-bottom: 5px;
}
input[type="range"] {
width: 100%;
}
.color-preview {
display: inline-block;
width: 20px;
height: 20px;
border-radius: 4px;
vertical-align: middle;
margin-left: 10px;
}
.instructions {
margin-top: 30px;
font-size: 0.9rem;
line-height: 1.5;
}
@media (max-width: 900px) {
.container {
flex-direction: column;
}
.controls {
margin-left: 0;
margin-top: 30px;
max-width: 400px;
}
}
</style>
</head>
<body>
<div class="container">
<h1>动态球型标签云</h1>
<div class="sphere-container">
<div class="sphere" id="sphere"></div>
</div>
<div class="controls">
<h2>控制面板</h2>
<div class="control-group">
<label for="rotationSpeed">旋转速度: <span id="speedValue">2</span></label>
<input type="range" id="rotationSpeed" min="0" max="5" step="0.1" value="2">
</div>
<div class="control-group">
<label for="tagColor">标签颜色:
<span class="color-preview" id="colorPreview"></span>
</label>
<input type="color" id="tagColor" value="#4A90E2">
</div>
<div class="control-group">
<label for="tagCount">标签数量: <span id="countValue">20</span></label>
<input type="range" id="tagCount" min="5" max="40" value="20">
</div>
<button id="resetButton">重置位置</button>
<div class="instructions">
<p>使用说明:</p>
<ul>
<li>将鼠标悬停在球体上并移动可以旋转球体</li>
<li>点击标签可以将其固定/取消固定</li>
<li>使用上方的控制面板调整效果</li>
</ul>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
// 配置
const sphere = document.getElementById('sphere');
const sphereContainer = document.querySelector('.sphere-container');
const rotationSpeedSlider = document.getElementById('rotationSpeed');
const speedValue = document.getElementById('speedValue');
const tagColorPicker = document.getElementById('tagColor');
const colorPreview = document.getElementById('colorPreview');
const tagCountSlider = document.getElementById('tagCount');
const countValue = document.getElementById('countValue');
const resetButton = document.getElementById('resetButton');
let tags = [];
let radius = 150;
let autoRotate = true;
let rotationSpeed = 2;
let tagColor = '#4A90E2';
let tagCount = 20;
let mouseX = 0;
let mouseY = 0;
let mouseDown = false;
let fixedTags = [];
// 初始化
function init() {
createTags();
updateColorPreview();
animate();
// 事件监听
sphereContainer.addEventListener('mousemove', handleMouseMove);
sphereContainer.addEventListener('mousedown', () => mouseDown = true);
sphereContainer.addEventListener('mouseup', () => mouseDown = false);
sphereContainer.addEventListener('mouseleave', () => mouseDown = false);
rotationSpeedSlider.addEventListener('input', function() {
rotationSpeed = parseFloat(this.value);
speedValue.textContent = rotationSpeed.toFixed(1);
});
tagColorPicker.addEventListener('input', function() {
tagColor = this.value;
updateTagColors();
updateColorPreview();
});
tagCountSlider.addEventListener('input', function() {
tagCount = parseInt(this.value);
countValue.textContent = tagCount;
createTags();
});
resetButton.addEventListener('click', resetSpherePosition);
}
// 创建标签
function createTags() {
// 清除现有标签
sphere.innerHTML = '';
tags = [];
fixedTags = [];
// 示例标签文本
const tagTexts = [
'JavaScript', 'HTML5', 'CSS3', 'React', 'Vue.js',
'Node.js', 'Python', 'Java', 'PHP', 'Ruby',
'Swift', 'Go', 'Rust', 'TypeScript', 'Angular',
'jQuery', 'Bootstrap', 'SASS', 'LESS', 'Webpack',
'Git', 'Docker', 'Kubernetes', 'AWS', 'Azure',
'MongoDB', 'MySQL', 'PostgreSQL', 'Redis', 'Firebase',
'GraphQL', 'REST API', 'UI/UX', 'Responsive Design', 'Agile',
'Machine Learning', 'Data Science', 'AI', 'IoT', 'Blockchain'
];
for (let i = 0; i < tagCount; i++) {
const tag = document.createElement('div');
tag.className = 'tag';
tag.textContent = tagTexts[i % tagTexts.length];
tag.style.backgroundColor = tagColor;
// 随机位置
const phi = Math.acos(-1 + (2 * i) / tagCount);
const theta = Math.sqrt(tagCount * Math.PI) * phi;
// 存储初始位置
const x = radius * Math.cos(theta) * Math.sin(phi);
const y = radius * Math.sin(theta) * Math.sin(phi);
const z = radius * Math.cos(phi);
tags.push({
element: tag,
x: x,
y: y,
z: z,
phi: phi,
theta: theta,
fixed: false
});
sphere.appendChild(tag);
// 点击事件 - 固定/取消固定标签
tag.addEventListener('click', function(e) {
e.stopPropagation();
const index = tags.findIndex(t => t.element === this);
if (index !== -1) {
tags[index].fixed = !tags[index].fixed;
if (tags[index].fixed) {
fixedTags.push(index);
this.style.boxShadow = '0 0 15px 5px rgba(255, 255, 255, 0.7)';
} else {
fixedTags = fixedTags.filter(idx => idx !== index);
this.style.boxShadow = '0 3px 10px rgba(0, 0, 0, 0.2)';
}
}
});
}
updateTagPositions();
}
// 更新标签位置
function updateTagPositions() {
tags.forEach(tag => {
tag.element.style.transform = `translate3d(${tag.x}px, ${tag.y}px, ${tag.z}px)`;
// 根据z坐标调整标签大小和透明度,创造深度感
const scale = 0.8 + (tag.z + radius) / (2 * radius) * 0.7;
const opacity = 0.6 + (tag.z + radius) / (2 * radius) * 0.4;
tag.element.style.opacity = opacity;
tag.element.style.fontSize = `${scale * 0.9}rem`;
tag.element.style.zIndex = Math.floor(scale * 100);
});
}
// 处理鼠标移动
function handleMouseMove(e) {
if (!mouseDown) return;
const rect = sphereContainer.getBoundingClientRect();
const centerX = rect.left + rect.width / 2;
const centerY = rect.top + rect.height / 2;
mouseX = (e.clientX - centerX) * 0.0005;
mouseY = (e.clientY - centerY) * 0.0005;
rotateSphere(mouseX, mouseY);
}
// 旋转球体
function rotateSphere(deltaX, deltaY) {
tags.forEach(tag => {
if (tag.fixed) return; // 跳过固定的标签
// 旋转计算
const x = tag.x;
const y = tag.y * Math.cos(deltaX) - tag.z * Math.sin(deltaX);
const z = tag.y * Math.sin(deltaX) + tag.z * Math.cos(deltaX);
const x2 = x * Math.cos(deltaY) + z * Math.sin(deltaY);
const y2 = y;
const z2 = -x * Math.sin(deltaY) + z * Math.cos(deltaY);
tag.x = x2;
tag.y = y2;
tag.z = z2;
});
updateTagPositions();
}
// 动画循环
function animate() {
requestAnimationFrame(animate);
if (autoRotate && !mouseDown) {
rotateSphere(0.001 * rotationSpeed, 0.0005 * rotationSpeed);
}
}
// 更新标签颜色
function updateTagColors() {
tags.forEach(tag => {
tag.element.style.backgroundColor = tagColor;
});
}
// 更新颜色预览
function updateColorPreview() {
colorPreview.style.backgroundColor = tagColor;
}
// 重置球体位置
function resetSpherePosition() {
createTags();
}
// 初始化应用
init();
});
</script>
</body>
</html>
```
## 功能说明
这个动态球型标签云具有以下功能:
1. **3D球体效果**:标签分布在3D球体表面,具有深度感和透视效果
2. **自动旋转**:球体会自动缓慢旋转展示所有标签
3. **鼠标交互**:可以用鼠标拖动旋转球体,从不同角度查看标签
4. **标签交互**:点击标签可以将其固定或取消固定
5. **自定义设置**:
- 调整旋转速度
- 更改标签颜色
- 调整标签数量
- 重置球体位置
## 技术实现
- 使用CSS 3D变换实现球体效果
- 使用JavaScript计算每个标签在球体表面的位置(使用球面坐标公式)
- 根据标签的Z坐标调整透明度和大小,增强3D效果
- 使用requestAnimationFrame实现平滑动画
您可以直接复制上面的代码到HTML文件中运行,或根据需要进行修改和扩展。 |
|