动态爱心树
1.柔和色彩方案:
主色调:柔粉色(#ffa7c4)和浅紫色(#f9f7fe)
背景:浅蓝色渐变(#f9f7fe到#e3f2fd)
文字:灰紫色(#5a5a7a)
2.动态效果:
分形算法生成的爱心树(每次生成形状都不同)
从树枝末端飘落的爱心动画
交互式控制面板可调整树形参数
悬停效果增强用户体验
3.视觉效果优化:
使用CSS渐变和阴影创造深度感
半透明玻璃态UI设计
爱心使用发光效果增强视觉吸引力
响应式设计适配各种屏幕尺寸
4.详细步骤说明:
5个实现步骤的详细解释
每个步骤有独立的卡片设计
步骤编号使用渐变圆形设计
5.交互功能:
生成新树按钮
添加爱心按钮
树枝角度调节滑块
树枝长度调节滑块
6.截图展示:
7.代码重现:
<!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 {font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;background: linear-gradient(135deg, #f9f7fe 0%, #e3f2fd 100%);color: #5a5a7a;min-height: 100vh;overflow-x: hidden;padding: 20px;}.container {max-width: 1200px;margin: 0 auto;display: flex;flex-direction: column;gap: 30px;}header {text-align: center;padding: 20px;background: rgba(255, 255, 255, 0.7);border-radius: 20px;box-shadow: 0 8px 32px rgba(149, 117, 205, 0.1);backdrop-filter: blur(10px);border: 1px solid rgba(255, 255, 255, 0.5);}h1 {font-size: 2.8rem;margin-bottom: 15px;color: #e86a92;text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.1);background: linear-gradient(45deg, #e86a92, #ffa7c4);-webkit-background-clip: text;-webkit-text-fill-color: transparent;}.subtitle {font-size: 1.2rem;color: #7a7a9e;max-width: 700px;margin: 0 auto;line-height: 1.6;}.content {display: flex;gap: 30px;flex-wrap: wrap;}.canvas-container {flex: 1;min-width: 300px;background: rgba(255, 255, 255, 0.8);border-radius: 20px;box-shadow: 0 12px 40px rgba(149, 117, 205, 0.15);overflow: hidden;position: relative;min-height: 600px;border: 1px solid rgba(255, 255, 255, 0.7);}#treeCanvas {width: 100%;height: 100%;display: block;background: rgba(249, 247, 254, 0.5);}.instructions {flex: 1;min-width: 300px;background: rgba(255, 255, 255, 0.8);border-radius: 20px;padding: 30px;box-shadow: 0 12px 40px rgba(149, 117, 205, 0.15);border: 1px solid rgba(255, 255, 255, 0.7);}.instructions h2 {color: #e86a92;margin-bottom: 20px;font-size: 1.8rem;display: flex;align-items: center;gap: 10px;}.instructions h2 i {font-size: 1.5rem;}.step {margin-bottom: 25px;padding: 20px;background: rgba(249, 247, 254, 0.6);border-radius: 15px;position: relative;overflow: hidden;transition: transform 0.3s ease;border-left: 4px solid #ffa7c4;}.step:hover {transform: translateY(-5px);background: rgba(255, 255, 255, 0.9);box-shadow: 0 8px 20px rgba(232, 106, 146, 0.1);}.step h3 {color: #7a7a9e;margin-bottom: 10px;font-size: 1.3rem;display: flex;align-items: center;gap: 8px;}.step p {line-height: 1.7;color: #5a5a7a;}.step-number {background: linear-gradient(45deg, #e86a92, #ffa7c4);color: white;width: 30px;height: 30px;border-radius: 50%;display: flex;align-items: center;justify-content: center;font-weight: bold;margin-right: 10px;}.controls {display: flex;justify-content: center;gap: 20px;flex-wrap: wrap;margin-top: 20px;}.btn {background: linear-gradient(45deg, #e86a92, #ffa7c4);color: white;border: none;padding: 14px 30px;border-radius: 50px;font-size: 1.1rem;cursor: pointer;transition: all 0.3s ease;box-shadow: 0 6px 15px rgba(232, 106, 146, 0.3);display: flex;align-items: center;gap: 8px;font-weight: 600;}.btn:hover {transform: translateY(-3px);box-shadow: 0 8px 20px rgba(232, 106, 146, 0.4);}.btn:active {transform: translateY(1px);}.btn-outline {background: transparent;border: 2px solid #e86a92;color: #e86a92;}.hearts-container {position: absolute;top: 0;left: 0;width: 100%;height: 100%;pointer-events: none;overflow: hidden;}.heart {position: absolute;font-size: 24px;top: -50px;animation: fall linear forwards;color: #ffa7c4;opacity: 0.7;text-shadow: 0 0 10px rgba(255, 167, 196, 0.5);}@keyframes fall {to {transform: translateY(100vh) rotate(360deg);opacity: 0;}}.slider-container {margin-top: 15px;padding: 15px;background: rgba(249, 247, 254, 0.6);border-radius: 15px;}.slider-label {display: flex;justify-content: space-between;margin-bottom: 10px;font-weight: 500;color: #7a7a9e;}input[type="range"] {width: 100%;height: 10px;border-radius: 5px;background: linear-gradient(to right, #e86a92, #ffa7c4);outline: none;-webkit-appearance: none;}input[type="range"]::-webkit-slider-thumb {-webkit-appearance: none;width: 22px;height: 22px;border-radius: 50%;background: white;border: 2px solid #e86a92;cursor: pointer;box-shadow: 0 2px 5px rgba(0,0,0,0.2);}footer {text-align: center;padding: 20px;color: #7a7a9e;font-size: 0.9rem;}@media (max-width: 768px) {.content {flex-direction: column;}h1 {font-size: 2.2rem;}}</style>
</head>
<body><div class="container"><header><h1>梦幻爱心树</h1><p class="subtitle">一个充满浪漫色彩的可视化项目,结合了分形树算法与动态爱心效果,创造出令人心动的视觉效果</p></header><div class="content"><div class="canvas-container"><canvas id="treeCanvas"></canvas><div class="hearts-container" id="heartsContainer"></div></div><div class="instructions"><h2><i>❤️</i> 实现步骤详解</h2><div class="step"><h3><span class="step-number">1</span> 画布初始化</h3><p>创建Canvas画布并设置尺寸为整个容器大小。初始化绘图上下文,为绘制爱心树做准备。</p></div><div class="step"><h3><span class="step-number">2</span> 分形树算法</h3><p>使用递归算法绘制树结构。从树干开始,每个分支点会分出两个新分支,长度和角度根据参数变化,形成自然的分形树结构。</p></div><div class="step"><h3><span class="step-number">3</span> 爱心绘制</h3><p>在树枝末端绘制爱心。爱心使用贝塞尔曲线绘制,填充柔和的粉色渐变,并添加发光效果增强视觉吸引力。</p></div><div class="step"><h3><span class="step-number">4</span> 飘落爱心动画</h3><p>创建多个爱心元素,设置随机位置和动画参数。每个爱心以不同速度和旋转角度飘落,形成浪漫的视觉效果。</p></div><div class="step"><h3><span class="step-number">5</span> 交互控制</h3><p>添加按钮和滑块,让用户可以重新生成树、调整树枝角度、长度和爱心数量,实现交互式体验。</p></div><div class="controls"><button class="btn" id="generateBtn"><i>🔄</i> 生成新树</button><button class="btn btn-outline" id="addHeartsBtn"><i>💖</i> 添加爱心</button></div><div class="slider-container"><div class="slider-label"><span>树枝角度</span><span id="angleValue">45°</span></div><input type="range" id="angleSlider" min="10" max="80" value="45"></div><div class="slider-container"><div class="slider-label"><span>树枝长度</span><span id="lengthValue">100</span></div><input type="range" id="lengthSlider" min="50" max="200" value="100"></div></div></div><footer><p>梦幻爱心树 | 可视化设计项目 | 使用HTML5 Canvas实现</p></footer></div><script>// 获取Canvas元素和上下文const canvas = document.getElementById('treeCanvas');const ctx = canvas.getContext('2d');const heartsContainer = document.getElementById('heartsContainer');// 设置Canvas尺寸function setupCanvas() {const container = canvas.parentElement;canvas.width = container.clientWidth;canvas.height = container.clientHeight;}// 树参数let treeParams = {startX: 0,startY: 0,angle: 45,branchLength: 100,depth: 10,branchWidth: 15,leafSize: 12};// 初始化setupCanvas();window.addEventListener('resize', setupCanvas);// 绘制爱心function drawHeart(x, y, size) {ctx.save();ctx.translate(x, y);// 创建爱心渐变const gradient = ctx.createRadialGradient(0, 0, size*0.2, 0, 0, size);gradient.addColorStop(0, '#ffd1dc');gradient.addColorStop(1, '#ffa7c4');ctx.fillStyle = gradient;ctx.shadowColor = 'rgba(232, 106, 146, 0.7)';ctx.shadowBlur = 15;ctx.beginPath();ctx.moveTo(0, 0);ctx.bezierCurveTo(size/2, -size/2,size, 0,0, size);ctx.bezierCurveTo(-size, 0,-size/2, -size/2,0, 0);ctx.fill();ctx.restore();}// 绘制树分支(递归函数)function drawBranch(x, y, angle, length, depth, width) {if (depth === 0) {// 在树枝末端绘制爱心drawHeart(x, y, treeParams.leafSize * (Math.random() * 0.5 + 0.8));return;}// 计算分支终点const endX = x - length * Math.sin(angle * Math.PI / 180);const endY = y - length * Math.cos(angle * Math.PI / 180);// 设置分支样式ctx.lineWidth = width;// 创建树枝渐变const gradient = ctx.createLinearGradient(x, y, endX, endY);gradient.addColorStop(0, '#8B4513');gradient.addColorStop(1, '#A0522D');ctx.strokeStyle = gradient;ctx.lineCap = 'round';// 绘制分支ctx.beginPath();ctx.moveTo(x, y);ctx.lineTo(endX, endY);ctx.stroke();// 递归绘制子分支const newLength = length * 0.75;const newWidth = width * 0.7;// 左分支drawBranch(endX, endY, angle + treeParams.angle + Math.random() * 5, newLength * (0.9 + Math.random() * 0.2), depth - 1, newWidth);// 右分支drawBranch(endX, endY, angle - treeParams.angle - Math.random() * 5, newLength * (0.9 + Math.random() * 0.2), depth - 1, newWidth);// 随机绘制一些额外的爱心if (Math.random() > 0.5 && depth < 6) {drawHeart(endX + (Math.random() - 0.5) * 30,endY + (Math.random() - 0.5) * 30,treeParams.leafSize * (0.5 + Math.random() * 0.5));}}// 绘制整棵树function drawTree() {ctx.clearRect(0, 0, canvas.width, canvas.height);// 设置树起点在底部中央treeParams.startX = canvas.width / 2;treeParams.startY = canvas.height - 50;// 绘制树干drawBranch(treeParams.startX, treeParams.startY, 0, treeParams.branchLength, treeParams.depth, treeParams.branchWidth);}// 创建飘落的爱心function createFallingHearts(count) {for (let i = 0; i < count; i++) {setTimeout(() => {const heart = document.createElement('div');heart.innerHTML = '❤️';heart.classList.add('heart');// 随机位置const left = Math.random() * 100;heart.style.left = `${left}%`;// 随机大小const size = 0.5 + Math.random() * 1.5;heart.style.fontSize = `${size}rem`;// 随机动画参数const duration = 5 + Math.random() * 10;const delay = Math.random() * 5;heart.style.animation = `fall ${duration}s linear ${delay}s forwards`;heartsContainer.appendChild(heart);// 动画结束后移除爱心setTimeout(() => {heart.remove();}, (duration + delay) * 1000);}, i * 300);}}// 初始化树和爱心drawTree();createFallingHearts(15);// 按钮事件监听document.getElementById('generateBtn').addEventListener('click', () => {drawTree();createFallingHearts(3);});document.getElementById('addHeartsBtn').addEventListener('click', () => {createFallingHearts(10);});// 滑块事件监听document.getElementById('angleSlider').addEventListener('input', (e) => {treeParams.angle = parseInt(e.target.value);document.getElementById('angleValue').textContent = `${treeParams.angle}°`;drawTree();});document.getElementById('lengthSlider').addEventListener('input', (e) => {treeParams.branchLength = parseInt(e.target.value);document.getElementById('lengthValue').textContent = treeParams.branchLength;drawTree();});// 自动添加爱心setInterval(() => {createFallingHearts(1);}, 1500);</script>
</body>
</html>