| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065 |
- // 全局变量
- let currentTheme = 'pastel';
- let currentStyle = 'cartoon';
- let currentCanvasSize = 128;
- let currentPixelSize = 8;
- let currentSocialMediaFormat = 'custom';
- let favorites = JSON.parse(localStorage.getItem('favorites')) || [];
- let avatarHistory = JSON.parse(localStorage.getItem('avatarHistory')) || [];
- let currentSeed = null;
- let useSeed = false;
- const maxHistoryItems = 50;
- // 社交媒体格式尺寸映射
- const socialMediaFormats = {
- facebook: 180,
- twitter: 400,
- instagram: 320,
- linkedin: 400,
- youtube: 800
- };
- // 编辑相关变量
- let isDrawing = false;
- let currentTool = 'brush';
- let currentColor = '#000000';
- let currentBrushSize = 1;
- let history = [];
- let historyIndex = -1;
- // 颜色主题
- const colorThemes = {
- pastel: ['#FFB6C1', '#FFD700', '#98FB98', '#87CEEB', '#DDA0DD', '#FFA07A'],
- vibrant: ['#FF6B6B', '#4ECDC4', '#45B7D1', '#FFA07A', '#98D8C8', '#F7DC6F'],
- dark: ['#2C3E50', '#34495E', '#7F8C8D', '#95A5A6', '#BDC3C7', '#ECF0F1'],
- monochrome: ['#000000', '#333333', '#666666', '#999999', '#CCCCCC', '#FFFFFF']
- };
- // 初始化
- window.addEventListener('DOMContentLoaded', () => {
- initializeApp();
- generateAvatar();
- loadHistory(); // 加载历史记录
- });
- function initializeApp() {
- // 界面切换
- setupNavigation();
-
- // 按钮事件
- setupButtons();
-
- // 设置
- setupSettings();
-
- // 加载收藏
- loadFavorites();
- }
- // 设置导航
- function setupNavigation() {
- const navBtns = document.querySelectorAll('.nav-btn');
- navBtns.forEach(btn => {
- btn.addEventListener('click', () => {
- const screen = btn.dataset.screen;
- showScreen(screen);
-
- // 更新导航按钮状态
- navBtns.forEach(b => b.classList.remove('active'));
- btn.classList.add('active');
- });
- });
-
- // 返回按钮
- document.getElementById('backToGenerate').addEventListener('click', () => {
- showScreen('generate-screen');
- document.getElementById('nav-generate').classList.add('active');
- document.getElementById('nav-favorites').classList.remove('active');
- });
-
- document.getElementById('backToGenerate2').addEventListener('click', () => {
- showScreen('generate-screen');
- document.getElementById('nav-generate').classList.add('active');
- document.getElementById('nav-settings').classList.remove('active');
- });
-
- document.getElementById('backToGenerate3').addEventListener('click', () => {
- showScreen('generate-screen');
- document.getElementById('nav-generate').classList.add('active');
- });
-
- document.getElementById('backToGenerate4').addEventListener('click', () => {
- showScreen('generate-screen');
- document.getElementById('nav-generate').classList.add('active');
- document.getElementById('nav-history').classList.remove('active');
- });
- }
- // 显示指定界面
- function showScreen(screenId) {
- const screens = document.querySelectorAll('.screen');
- screens.forEach(screen => screen.classList.remove('active'));
- document.getElementById(screenId).classList.add('active');
- }
- // 设置按钮事件
- function setupButtons() {
- // 重新生成按钮
- document.getElementById('regenerateBtn').addEventListener('click', generateAvatar);
-
- // 保存按钮
- document.getElementById('saveBtn').addEventListener('click', saveAvatar);
-
- // 编辑按钮
- document.getElementById('editBtn').addEventListener('click', openEditScreen);
-
- // 收藏按钮
- document.getElementById('favoriteBtn').addEventListener('click', addToFavorites);
-
- // 下载按钮
- document.getElementById('downloadBtn').addEventListener('click', downloadAvatar);
-
- // 主题按钮
- const themeBtns = document.querySelectorAll('.theme-btn');
- themeBtns.forEach(btn => {
- btn.addEventListener('click', () => {
- currentTheme = btn.dataset.theme;
- themeBtns.forEach(b => b.classList.remove('active'));
- btn.classList.add('active');
- generateAvatar();
- });
- });
-
- // 风格按钮
- const styleBtns = document.querySelectorAll('.style-btn');
- styleBtns.forEach(btn => {
- btn.addEventListener('click', () => {
- currentStyle = btn.dataset.style;
- styleBtns.forEach(b => b.classList.remove('active'));
- btn.classList.add('active');
- generateAvatar();
- });
- });
-
- // 细节按钮
- const detailBtns = document.querySelectorAll('.detail-btn');
- detailBtns.forEach(btn => {
- btn.addEventListener('click', () => {
- // 随机化特定细节
- generateAvatarWithFocus(btn.dataset.detail);
- });
- });
-
- // 社交媒体格式按钮
- const socialBtns = document.querySelectorAll('.social-options .theme-btn');
- socialBtns.forEach(btn => {
- btn.addEventListener('click', () => {
- const format = btn.dataset.format;
- setSocialMediaFormat(format);
- });
- });
-
- // 种子相关按钮
- setupSeedButtons();
-
- // 编辑界面按钮
- setupEditButtons();
-
- // 历史记录按钮
- const clearHistoryBtn = document.getElementById('clearHistoryBtn');
- if (clearHistoryBtn) {
- clearHistoryBtn.addEventListener('click', clearHistory);
- }
- }
- // 设置设置选项
- function setupSettings() {
- // 画布大小
- const canvasSizeSelect = document.getElementById('canvasSize');
- canvasSizeSelect.addEventListener('change', (e) => {
- currentCanvasSize = parseInt(e.target.value);
- currentSocialMediaFormat = 'custom';
- updateCanvasSize();
- generateAvatar();
- });
-
- // 社交媒体格式
- const socialMediaFormatSelect = document.getElementById('socialMediaFormat');
- socialMediaFormatSelect.addEventListener('change', (e) => {
- currentSocialMediaFormat = e.target.value;
-
- if (currentSocialMediaFormat !== 'custom') {
- // 设置为对应社交媒体格式的尺寸
- currentCanvasSize = socialMediaFormats[currentSocialMediaFormat];
- canvasSizeSelect.value = currentCanvasSize;
- updateCanvasSize();
- generateAvatar();
- }
- });
-
- // 像素大小
- const pixelSizeSelect = document.getElementById('pixelSize');
- pixelSizeSelect.addEventListener('change', (e) => {
- currentPixelSize = parseInt(e.target.value);
- generateAvatar();
- });
-
- // 界面主题
- const appThemeSelect = document.getElementById('appTheme');
- appThemeSelect.addEventListener('change', (e) => {
- const theme = e.target.value;
- document.body.className = theme === 'dark' ? 'dark-theme' : '';
- localStorage.setItem('appTheme', theme);
- });
-
- // 加载保存的主题
- const savedTheme = localStorage.getItem('appTheme') || 'light';
- appThemeSelect.value = savedTheme;
- document.body.className = savedTheme === 'dark' ? 'dark-theme' : '';
-
- // 清空收藏
- document.getElementById('clearFavorites').addEventListener('click', () => {
- if (confirm('确定要清空所有收藏吗?')) {
- favorites = [];
- localStorage.setItem('favorites', JSON.stringify(favorites));
- loadFavorites();
- }
- });
- }
- // 设置编辑界面按钮
- function setupEditButtons() {
- // 返回按钮
- document.getElementById('backToGenerate3').addEventListener('click', () => {
- showScreen('generate-screen');
- document.getElementById('nav-generate').classList.add('active');
- });
-
- // 颜色选择器
- document.getElementById('colorPicker').addEventListener('input', (e) => {
- currentColor = e.target.value;
- });
-
- // 画笔大小
- document.getElementById('brushSize').addEventListener('change', (e) => {
- currentBrushSize = parseInt(e.target.value);
- });
-
- // 工具按钮
- const toolBtns = document.querySelectorAll('.tool-btn');
- toolBtns.forEach(btn => {
- btn.addEventListener('click', () => {
- currentTool = btn.dataset.tool;
- toolBtns.forEach(b => b.classList.remove('active'));
- btn.classList.add('active');
- });
- });
-
- // 撤销/重做按钮
- document.getElementById('undoBtn').addEventListener('click', undo);
- document.getElementById('redoBtn').addEventListener('click', redo);
-
- // 保存编辑
- document.getElementById('saveEditBtn').addEventListener('click', saveEdit);
- }
- // 打开编辑界面
- function openEditScreen() {
- const avatarCanvas = document.getElementById('avatarCanvas');
- const editCanvas = document.getElementById('editCanvas');
- const ctx = editCanvas.getContext('2d');
-
- // 设置编辑画布大小与生成画布一致
- editCanvas.width = avatarCanvas.width;
- editCanvas.height = avatarCanvas.height;
-
- // 复制当前头像到编辑画布
- ctx.drawImage(avatarCanvas, 0, 0);
-
- // 初始化编辑工具
- currentTool = 'brush';
- currentColor = '#000000';
- currentBrushSize = 1;
-
- // 重置历史记录
- history = [];
- historyIndex = -1;
- saveToHistory();
-
- // 设置画布事件监听
- setupCanvasEventListeners();
-
- // 显示编辑界面
- showScreen('edit-screen');
- }
- // 设置画布事件监听
- function setupCanvasEventListeners() {
- const canvas = document.getElementById('editCanvas');
-
- // 移除旧的事件监听
- canvas.removeEventListener('mousedown', startDrawing);
- canvas.removeEventListener('mousemove', draw);
- canvas.removeEventListener('mouseup', stopDrawing);
- canvas.removeEventListener('mouseout', stopDrawing);
-
- canvas.removeEventListener('touchstart', startDrawing);
- canvas.removeEventListener('touchmove', draw);
- canvas.removeEventListener('touchend', stopDrawing);
-
- // 添加新的事件监听
- canvas.addEventListener('mousedown', startDrawing);
- canvas.addEventListener('mousemove', draw);
- canvas.addEventListener('mouseup', stopDrawing);
- canvas.addEventListener('mouseout', stopDrawing);
-
- canvas.addEventListener('touchstart', startDrawing);
- canvas.addEventListener('touchmove', draw);
- canvas.addEventListener('touchend', stopDrawing);
- }
- // 开始绘制
- function startDrawing(e) {
- isDrawing = true;
- draw(e);
- }
- // 绘制
- function draw(e) {
- if (!isDrawing) return;
-
- const canvas = document.getElementById('editCanvas');
- const ctx = canvas.getContext('2d');
-
- // 获取鼠标/触摸位置
- let rect = canvas.getBoundingClientRect();
- let x, y;
-
- if (e.type.startsWith('mouse')) {
- x = e.clientX - rect.left;
- y = e.clientY - rect.top;
- } else {
- e.preventDefault();
- x = e.touches[0].clientX - rect.left;
- y = e.touches[0].clientY - rect.top;
- }
-
- // 转换为像素坐标(对齐到像素网格)
- x = Math.floor(x / currentPixelSize) * currentPixelSize;
- y = Math.floor(y / currentPixelSize) * currentPixelSize;
-
- // 根据工具执行不同操作
- switch (currentTool) {
- case 'brush':
- drawBrush(ctx, x, y);
- break;
- case 'eraser':
- drawEraser(ctx, x, y);
- break;
- case 'fill':
- fillBucket(ctx, x, y);
- isDrawing = false;
- break;
- }
- }
- // 停止绘制
- function stopDrawing() {
- if (isDrawing) {
- isDrawing = false;
- saveToHistory();
- }
- }
- // 画笔绘制
- function drawBrush(ctx, x, y) {
- ctx.fillStyle = currentColor;
- ctx.fillRect(x, y, currentBrushSize * currentPixelSize, currentBrushSize * currentPixelSize);
- }
- // 橡皮擦绘制
- function drawEraser(ctx, x, y) {
- ctx.clearRect(x, y, currentBrushSize * currentPixelSize, currentBrushSize * currentPixelSize);
- }
- // 填充工具
- function fillBucket(ctx, x, y) {
- const canvas = ctx.canvas;
- const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
- const data = imageData.data;
-
- const targetColor = getPixelColor(data, x, y, canvas.width);
- const fillColor = hexToRgb(currentColor);
-
- if (colorsMatch(targetColor, fillColor)) return;
-
- const stack = [{x, y}];
-
- while (stack.length > 0) {
- const pixel = stack.pop();
- const currentPixelColor = getPixelColor(data, pixel.x, pixel.y, canvas.width);
-
- if (colorsMatch(currentPixelColor, targetColor)) {
- setPixelColor(data, pixel.x, pixel.y, fillColor, canvas.width);
-
- // 检查相邻像素
- if (pixel.x > 0) stack.push({x: pixel.x - currentPixelSize, y: pixel.y});
- if (pixel.x < canvas.width - currentPixelSize) stack.push({x: pixel.x + currentPixelSize, y: pixel.y});
- if (pixel.y > 0) stack.push({x: pixel.x, y: pixel.y - currentPixelSize});
- if (pixel.y < canvas.height - currentPixelSize) stack.push({x: pixel.x, y: pixel.y + currentPixelSize});
- }
- }
-
- ctx.putImageData(imageData, 0, 0);
- }
- // 获取像素颜色
- function getPixelColor(data, x, y, width) {
- const index = (y * width + x) * 4;
- return {
- r: data[index],
- g: data[index + 1],
- b: data[index + 2],
- a: data[index + 3]
- };
- }
- // 设置像素颜色
- function setPixelColor(data, x, y, color, width) {
- const index = (y * width + x) * 4;
- data[index] = color.r;
- data[index + 1] = color.g;
- data[index + 2] = color.b;
- data[index + 3] = 255; // 不透明
- }
- // 颜色匹配
- function colorsMatch(color1, color2) {
- return color1.r === color2.r && color1.g === color2.g && color1.b === color2.b;
- }
- // 十六进制转RGB
- function hexToRgb(hex) {
- const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
- return result ? {
- r: parseInt(result[1], 16),
- g: parseInt(result[2], 16),
- b: parseInt(result[3], 16)
- } : null;
- }
- // 保存到历史记录
- function saveToHistory() {
- const canvas = document.getElementById('editCanvas');
- const dataURL = canvas.toDataURL();
-
- // 移除当前索引之后的历史记录
- if (historyIndex < history.length - 1) {
- history = history.slice(0, historyIndex + 1);
- }
-
- history.push(dataURL);
- historyIndex = history.length - 1;
- }
- // 撤销
- function undo() {
- if (historyIndex > 0) {
- historyIndex--;
- loadFromHistory();
- }
- }
- // 重做
- function redo() {
- if (historyIndex < history.length - 1) {
- historyIndex++;
- loadFromHistory();
- }
- }
- // 从历史记录加载
- function loadFromHistory() {
- const canvas = document.getElementById('editCanvas');
- const ctx = canvas.getContext('2d');
- const img = new Image();
-
- img.onload = function() {
- ctx.clearRect(0, 0, canvas.width, canvas.height);
- ctx.drawImage(img, 0, 0);
- };
-
- img.src = history[historyIndex];
- }
- // 保存编辑
- function saveEdit() {
- const editCanvas = document.getElementById('editCanvas');
- const avatarCanvas = document.getElementById('avatarCanvas');
- const ctx = avatarCanvas.getContext('2d');
-
- // 设置生成画布大小与编辑画布一致
- avatarCanvas.width = editCanvas.width;
- avatarCanvas.height = editCanvas.height;
-
- // 复制编辑后的头像回生成画布
- ctx.drawImage(editCanvas, 0, 0);
-
- // 返回生成界面
- showScreen('generate-screen');
- document.getElementById('nav-generate').classList.add('active');
-
- alert('编辑已保存!');
- }
- // 设置种子相关按钮
- function setupSeedButtons() {
- const seedInput = document.getElementById('seedInput');
- const copySeedBtn = document.getElementById('copySeedBtn');
- const randomSeedBtn = document.getElementById('randomSeedBtn');
-
- // 种子输入事件
- seedInput.addEventListener('input', (e) => {
- setSeed(e.target.value);
- });
-
- // 复制种子按钮
- copySeedBtn.addEventListener('click', () => {
- const seedText = seedInput.value;
- if (seedText) {
- navigator.clipboard.writeText(seedText).then(() => {
- alert('种子已复制到剪贴板!');
- }).catch(err => {
- console.error('复制失败:', err);
- alert('复制失败,请手动复制');
- });
- } else {
- alert('没有可复制的种子');
- }
- });
-
- // 生成随机种子按钮
- randomSeedBtn.addEventListener('click', () => {
- const randomSeed = generateRandomSeed();
- seedInput.value = randomSeed;
- setSeed(randomSeed);
- generateAvatar();
- });
-
- // 当重新生成头像时,如果没有种子则生成一个
- document.getElementById('regenerateBtn').addEventListener('click', () => {
- if (!seedInput.value.trim()) {
- const randomSeed = generateRandomSeed();
- seedInput.value = randomSeed;
- setSeed(randomSeed);
- }
- });
- }
- // 设置社交媒体格式
- function setSocialMediaFormat(format) {
- currentSocialMediaFormat = format;
-
- // 设置为对应社交媒体格式的尺寸
- currentCanvasSize = socialMediaFormats[currentSocialMediaFormat];
-
- // 更新设置界面中的选择器
- const canvasSizeSelect = document.getElementById('canvasSize');
- const socialMediaFormatSelect = document.getElementById('socialMediaFormat');
-
- canvasSizeSelect.value = currentCanvasSize;
- socialMediaFormatSelect.value = currentSocialMediaFormat;
-
- // 更新画布大小
- updateCanvasSize();
-
- // 重新生成头像
- generateAvatar();
-
- // 更新社交媒体格式按钮的激活状态
- const socialBtns = document.querySelectorAll('.social-options .theme-btn');
- socialBtns.forEach(btn => {
- btn.classList.remove('active');
- if (btn.dataset.format === format) {
- btn.classList.add('active');
- }
- });
- }
- // 更新画布大小
- function updateCanvasSize() {
- const canvas = document.getElementById('avatarCanvas');
- canvas.width = currentCanvasSize;
- canvas.height = currentCanvasSize;
- }
- // 生成头像
- function generateAvatar() {
- const canvas = document.getElementById('avatarCanvas');
- const ctx = canvas.getContext('2d');
-
- // 如果有种子输入但未设置,先设置种子
- const seedInput = document.getElementById('seedInput');
- if (seedInput && seedInput.value && seedInput.value.trim() !== '') {
- setSeed(seedInput.value);
- }
-
- // 清空画布
- ctx.clearRect(0, 0, canvas.width, canvas.height);
-
- // 绘制背景
- ctx.fillStyle = getRandomColor();
- ctx.fillRect(0, 0, canvas.width, canvas.height);
-
- // 根据风格生成头像
- switch(currentStyle) {
- case 'cartoon':
- drawCartoonStyle(ctx);
- break;
- case 'pixelart':
- drawPixelArtStyle(ctx);
- break;
- case 'minimal':
- drawMinimalStyle(ctx);
- break;
- }
-
- // 保存到历史记录
- saveAvatarToHistory();
- }
- // 生成特定细节的头像
- function generateAvatarWithFocus(focus) {
- const canvas = document.getElementById('avatarCanvas');
- const ctx = canvas.getContext('2d');
-
- // 保存当前头像
- const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
-
- // 重新生成
- generateAvatar();
-
- // 根据焦点重新绘制特定部分
- switch(focus) {
- case 'eyes':
- drawEyes(ctx);
- break;
- case 'nose':
- drawNose(ctx);
- break;
- case 'mouth':
- drawMouth(ctx);
- break;
- case 'accessories':
- drawAccessories(ctx);
- break;
- }
- }
- // 基于种子的随机数生成器
- function seededRandom(seed) {
- let x = Math.sin(seed) * 10000;
- return x - Math.floor(x);
- }
- // 获取当前随机数生成器
- function getRandom() {
- if (useSeed && currentSeed !== null) {
- currentSeed = (currentSeed + 0.123456789) % 1;
- return seededRandom(currentSeed);
- }
- return Math.random();
- }
- // 设置随机种子
- function setSeed(seed) {
- if (seed && seed.trim() !== '') {
- // 将字符串种子转换为数字
- let numSeed = 0;
- for (let i = 0; i < seed.length; i++) {
- numSeed += seed.charCodeAt(i) * Math.pow(31, i);
- }
- currentSeed = numSeed % 1;
- useSeed = true;
- } else {
- useSeed = false;
- currentSeed = null;
- }
- }
- // 生成随机种子字符串
- function generateRandomSeed() {
- const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
- let result = '';
- for (let i = 0; i < 10; i++) {
- result += chars.charAt(Math.floor(Math.random() * chars.length));
- }
- return result;
- }
- // 获取随机颜色
- function getRandomColor() {
- const colors = colorThemes[currentTheme];
- return colors[Math.floor(getRandom() * colors.length)];
- }
- // 卡通风格
- function drawCartoonStyle(ctx) {
- const centerX = ctx.canvas.width / 2;
- const centerY = ctx.canvas.height / 2;
- const size = Math.min(ctx.canvas.width, ctx.canvas.height) * 0.8;
-
- // 头部
- ctx.fillStyle = getRandomColor();
- ctx.beginPath();
- ctx.arc(centerX, centerY, size / 2, 0, Math.PI * 2);
- ctx.fill();
-
- drawEyes(ctx);
- drawNose(ctx);
- drawMouth(ctx);
- drawAccessories(ctx);
- }
- // 像素艺术风格
- function drawPixelArtStyle(ctx) {
- const gridSize = currentPixelSize;
- const cols = Math.floor(ctx.canvas.width / gridSize);
- const rows = Math.floor(ctx.canvas.height / gridSize);
-
- // 头部轮廓
- for (let y = 2; y < rows - 2; y++) {
- for (let x = 2; x < cols - 2; x++) {
- if ((x === 2 || x === cols - 3) && (y > 4 && y < rows - 5)) continue;
- if (Math.abs(x - cols/2) + Math.abs(y - rows/2) < rows/2 - 1) {
- ctx.fillStyle = getRandomColor();
- ctx.fillRect(x * gridSize, y * gridSize, gridSize, gridSize);
- }
- }
- }
-
- // 眼睛
- drawPixelEyes(ctx, gridSize, cols, rows);
-
- // 嘴巴
- drawPixelMouth(ctx, gridSize, cols, rows);
- }
- // 简约风格
- function drawMinimalStyle(ctx) {
- const centerX = ctx.canvas.width / 2;
- const centerY = ctx.canvas.height / 2;
- const size = Math.min(ctx.canvas.width, ctx.canvas.height) * 0.6;
-
- // 头部
- ctx.fillStyle = getRandomColor();
- ctx.fillRect(centerX - size/2, centerY - size/2, size, size);
-
- // 眼睛
- const eyeSize = size * 0.1;
- ctx.fillStyle = '#000000';
- ctx.fillRect(centerX - size/4 - eyeSize/2, centerY - size/6, eyeSize, eyeSize);
- ctx.fillRect(centerX + size/4 - eyeSize/2, centerY - size/6, eyeSize, eyeSize);
-
- // 嘴巴
- ctx.fillRect(centerX - size/6, centerY + size/6, size/3, eyeSize/2);
- }
- // 绘制眼睛
- function drawEyes(ctx) {
- const centerX = ctx.canvas.width / 2;
- const centerY = ctx.canvas.height / 2;
- const eyeSize = Math.min(ctx.canvas.width, ctx.canvas.height) * 0.15;
-
- ctx.fillStyle = '#FFFFFF';
- ctx.beginPath();
- ctx.arc(centerX - eyeSize * 1.5, centerY - eyeSize/2, eyeSize, 0, Math.PI * 2);
- ctx.arc(centerX + eyeSize * 1.5, centerY - eyeSize/2, eyeSize, 0, Math.PI * 2);
- ctx.fill();
-
- ctx.fillStyle = '#000000';
- ctx.beginPath();
- ctx.arc(centerX - eyeSize * 1.5, centerY - eyeSize/2, eyeSize * 0.4, 0, Math.PI * 2);
- ctx.arc(centerX + eyeSize * 1.5, centerY - eyeSize/2, eyeSize * 0.4, 0, Math.PI * 2);
- ctx.fill();
- }
- // 绘制鼻子
- function drawNose(ctx) {
- const centerX = ctx.canvas.width / 2;
- const centerY = ctx.canvas.height / 2;
- const noseSize = Math.min(ctx.canvas.width, ctx.canvas.height) * 0.08;
-
- ctx.fillStyle = getRandomColor();
- ctx.beginPath();
- ctx.arc(centerX, centerY, noseSize, 0, Math.PI * 2);
- ctx.fill();
- }
- // 绘制嘴巴
- function drawMouth(ctx) {
- const centerX = ctx.canvas.width / 2;
- const centerY = ctx.canvas.height / 2;
- const mouthSize = Math.min(ctx.canvas.width, ctx.canvas.height) * 0.25;
-
- ctx.fillStyle = '#FF0000';
- ctx.beginPath();
- ctx.arc(centerX, centerY + mouthSize/3, mouthSize/2, 0, Math.PI);
- ctx.fill();
- }
- // 绘制装饰
- function drawAccessories(ctx) {
- const centerX = ctx.canvas.width / 2;
- const centerY = ctx.canvas.height / 2;
- const size = Math.min(ctx.canvas.width, ctx.canvas.height) * 0.8;
-
- // 随机添加装饰
- const accessoryType = Math.floor(getRandom() * 3);
-
- switch(accessoryType) {
- case 0: // 帽子
- ctx.fillStyle = getRandomColor();
- ctx.fillRect(centerX - size/3, centerY - size/2 - size/6, size * 2/3, size/6);
- ctx.fillRect(centerX - size/2.5, centerY - size/2, size * 2/5, size/10);
- break;
- case 1: // 眼镜
- ctx.strokeStyle = getRandomColor();
- ctx.lineWidth = 3;
- ctx.beginPath();
- ctx.arc(centerX - size/4, centerY - size/6, size/8, 0, Math.PI * 2);
- ctx.arc(centerX + size/4, centerY - size/6, size/8, 0, Math.PI * 2);
- ctx.stroke();
- ctx.beginPath();
- ctx.moveTo(centerX - size/8, centerY - size/6);
- ctx.lineTo(centerX + size/8, centerY - size/6);
- ctx.stroke();
- break;
- case 2: // 耳朵
- ctx.fillStyle = getRandomColor();
- ctx.beginPath();
- ctx.arc(centerX - size/2, centerY, size/6, 0, Math.PI * 2);
- ctx.arc(centerX + size/2, centerY, size/6, 0, Math.PI * 2);
- ctx.fill();
- break;
- }
- }
- // 绘制像素风格眼睛
- function drawPixelEyes(ctx, gridSize, cols, rows) {
- const centerX = cols / 2;
- const centerY = rows / 2;
-
- ctx.fillStyle = '#FFFFFF';
- // 左眼
- for (let y = centerY - 2; y <= centerY + 1; y++) {
- for (let x = centerX - 4; x <= centerX - 2; x++) {
- ctx.fillRect(x * gridSize, y * gridSize, gridSize, gridSize);
- }
- }
- // 右眼
- for (let y = centerY - 2; y <= centerY + 1; y++) {
- for (let x = centerX + 2; x <= centerX + 4; x++) {
- ctx.fillRect(x * gridSize, y * gridSize, gridSize, gridSize);
- }
- }
-
- ctx.fillStyle = '#000000';
- // 左瞳孔
- ctx.fillRect((centerX - 3) * gridSize, centerY * gridSize, gridSize, gridSize);
- // 右瞳孔
- ctx.fillRect((centerX + 3) * gridSize, centerY * gridSize, gridSize, gridSize);
- }
- // 绘制像素风格嘴巴
- function drawPixelMouth(ctx, gridSize, cols, rows) {
- const centerX = cols / 2;
- const centerY = rows / 2;
-
- ctx.fillStyle = '#FF0000';
- for (let x = centerX - 3; x <= centerX + 3; x++) {
- ctx.fillRect(x * gridSize, (centerY + 3) * gridSize, gridSize, gridSize);
- }
- for (let x = centerX - 2; x <= centerX + 2; x++) {
- ctx.fillRect(x * gridSize, (centerY + 4) * gridSize, gridSize, gridSize);
- }
- }
- // 保存头像
- function saveAvatar() {
- const canvas = document.getElementById('avatarCanvas');
- const dataURL = canvas.toDataURL('image/png');
-
- // 如果自动保存开启,则保存到本地
- if (document.getElementById('autoSave').checked) {
- localStorage.setItem('lastAvatar', dataURL);
- alert('头像已保存!');
- }
- }
- // 添加到收藏
- function addToFavorites() {
- const canvas = document.getElementById('avatarCanvas');
- const dataURL = canvas.toDataURL('image/png');
-
- // 检查是否已存在
- const exists = favorites.some(fav => fav.dataURL === dataURL);
- if (exists) {
- alert('该头像已在收藏中!');
- return;
- }
-
- favorites.push({
- id: Date.now(),
- dataURL: dataURL,
- timestamp: new Date().toISOString()
- });
-
- localStorage.setItem('favorites', JSON.stringify(favorites));
- loadFavorites();
- alert('头像已添加到收藏!');
- }
- // 下载头像
- function downloadAvatar() {
- const canvas = document.getElementById('avatarCanvas');
- const link = document.createElement('a');
- link.download = `pixel-avatar-${Date.now()}.png`;
- link.href = canvas.toDataURL('image/png');
- link.click();
- }
- // 加载收藏
- function loadFavorites() {
- const grid = document.getElementById('favorites-grid');
- grid.innerHTML = '';
-
- if (favorites.length === 0) {
- grid.innerHTML = '<p style="text-align: center; padding: 20px;">暂无收藏</p>';
- return;
- }
-
- favorites.forEach(fav => {
- const item = document.createElement('div');
- item.className = 'favorite-item';
-
- const img = document.createElement('img');
- img.src = fav.dataURL;
- img.alt = '收藏的头像';
-
- const removeBtn = document.createElement('button');
- removeBtn.className = 'remove-favorite';
- removeBtn.textContent = '×';
- removeBtn.addEventListener('click', () => removeFavorite(fav.id));
-
- item.appendChild(img);
- item.appendChild(removeBtn);
- grid.appendChild(item);
- });
- }
- // 移除收藏
- function removeFavorite(id) {
- favorites = favorites.filter(fav => fav.id !== id);
- localStorage.setItem('favorites', JSON.stringify(favorites));
- loadFavorites();
- }
- // 自动保存
- window.addEventListener('beforeunload', () => {
- if (document.getElementById('autoSave').checked) {
- saveAvatar();
- }
- });
- // 保存头像到历史记录
- function saveAvatarToHistory() {
- const canvas = document.getElementById('avatarCanvas');
- const dataURL = canvas.toDataURL('image/png');
- const seedInput = document.getElementById('seedInput');
- const seed = seedInput.value || 'random';
-
- // 检查是否与最近的历史记录相同
- if (avatarHistory.length > 0 && avatarHistory[0].dataURL === dataURL) {
- return;
- }
-
- // 添加新记录到历史
- avatarHistory.unshift({
- id: Date.now(),
- dataURL: dataURL,
- seed: seed,
- timestamp: new Date().toISOString()
- });
-
- // 限制历史记录数量
- if (avatarHistory.length > maxHistoryItems) {
- avatarHistory = avatarHistory.slice(0, maxHistoryItems);
- }
-
- localStorage.setItem('avatarHistory', JSON.stringify(avatarHistory));
-
- // 如果当前在历史记录界面,更新显示
- if (document.getElementById('history-screen').classList.contains('active')) {
- loadHistory();
- }
- }
- // 加载历史记录
- function loadHistory() {
- const grid = document.getElementById('history-grid');
- grid.innerHTML = '';
-
- if (avatarHistory.length === 0) {
- grid.innerHTML = '<p style="text-align: center; padding: 20px;">暂无历史记录</p>';
- return;
- }
-
- avatarHistory.forEach(item => {
- const historyItem = document.createElement('div');
- historyItem.className = 'favorite-item';
-
- const img = document.createElement('img');
- img.src = item.dataURL;
- img.alt = `历史头像 ${new Date(item.timestamp).toLocaleString()}`;
-
- // 添加点击事件,可查看详细信息
- img.addEventListener('click', () => {
- // 将历史记录中的头像恢复到生成界面
- const avatarCanvas = document.getElementById('avatarCanvas');
- const ctx = avatarCanvas.getContext('2d');
- const historyImg = new Image();
- historyImg.onload = function() {
- avatarCanvas.width = historyImg.width;
- avatarCanvas.height = historyImg.height;
- ctx.drawImage(historyImg, 0, 0);
-
- // 设置种子
- const seedInput = document.getElementById('seedInput');
- seedInput.value = item.seed;
- if (item.seed !== 'random') {
- setSeed(item.seed);
- }
-
- // 切换到生成界面
- showScreen('generate-screen');
- document.getElementById('nav-generate').classList.add('active');
- document.getElementById('nav-history').classList.remove('active');
- };
- historyImg.src = item.dataURL;
- });
-
- historyItem.appendChild(img);
- grid.appendChild(historyItem);
- });
- }
- // 清空历史记录
- function clearHistory() {
- if (confirm('确定要清空所有历史记录吗?')) {
- avatarHistory = [];
- localStorage.removeItem('avatarHistory');
- loadHistory();
- alert('历史记录已清空!');
- }
- }
|