卡厄思
梦
境
菜单
首页
回到首页
WIKI工具
全站样式
全站JS
修改导航栏
测试
沙盒
可视化管理器
战斗员管理器
卡牌管理器
伙伴管理器
装备管理器
词典管理器
图鉴
战斗员
伙伴
装备
怪物卡牌
中立卡牌
词典
小工具
配队模拟器
节奏榜生成器
搜索
链入页面
相关更改
特殊页面
页面信息
最近更改
登录
微件
查看“︁TierListMaker”︁的源代码
←
微件:TierListMaker
因为以下原因,您没有权限编辑该页面:
您请求的操作仅限属于该用户组的用户执行:
用户
您没有权限编辑
微件
命名空间内的页面。
您可以查看和复制此页面的源代码。
<includeonly> <style> .tierlist-controls { display: flex; gap: 8px; margin: 8px 0 12px 0; } .btn { display: inline-block; padding: 6px 12px; background: #f0f0f0; border: 1px solid #ccc; color: #333; border-radius: 4px; cursor: pointer; user-select: none; } .btn:hover { background: #e6e6e6; } .btn.primary { background: #4a8cf6; color: #fff; border-color: #3b78de; } .btn.primary:hover { background: #3b78de; } .tierlist-table { width: 100%; table-layout: fixed; } .tier-row .tier-head { position: relative; width: 120px; color: #fff; text-align: center; font-size: 18px; font-weight: bold; padding: 8px; white-space: nowrap; border: 1px solid #ccc; background: #555; } .tier-row .tier-cell { border: 1px solid #ccc; padding: 0px; } .tier-tools { position: absolute; right: 6px; top: 6px; display: flex; gap: 6px; } .color-toggle { width: 18px; height: 18px; border-radius: 3px; border: 1px solid rgba(0,0,0,0.2); cursor: pointer; background: rgba(255,255,255,0.6); } .delete-row { font-size: 12px; padding: 2px 6px; border-radius: 3px; background: rgba(0,0,0,0.1); cursor: pointer; } .delete-row:hover { background: rgba(0,0,0,0.2); } .tier-dropzone { min-height: 112px; display: flex; flex-wrap: wrap; gap: 6px; align-items: flex-start; } .tier-dropzone.pool { border: 2px dashed #ccc; padding: 8px; border-radius: 6px; background: #fafafa; } .pool-wrapper { margin-top: 12px; } .pool-header { font-weight: bold; margin-bottom: 6px; } .avatar-frame { position: relative; display: inline-block; vertical-align: top; border: 3px solid #ccc; border-radius: 5px; overflow: hidden; box-shadow: 0 2px 5px rgba(0,0,0,0.1); background: #f5f5f5; transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease; cursor: move; } .avatar-frame.dragging { opacity: 0.7; transform: scale(1.03); border-color: #4a8cf6; z-index: 10; } .avatar-frame img { display: block; width: 100px; height: 100px; object-fit: cover; pointer-events: none; -webkit-user-drag: none; } .avatar-name { position: absolute; left: 0; bottom: 0; padding: 2px 8px; color: white; font-size: 12px; font-weight: bold; text-shadow: 0 0 2px black, 0 0 2px black; white-space: nowrap; max-width: 100%; overflow: hidden; text-overflow: ellipsis; border-top-right-radius: 3px; } .color-palette { position: absolute; display: none; gap: 6px; flex-wrap: wrap; width: 210px; padding: 8px; background: #fff; border: 1px solid #ccc; box-shadow: 0 2px 8px rgba(0,0,0,0.15); border-radius: 6px; z-index: 9999; } .color-swatch { width: 24px; height: 24px; border-radius: 4px; border: 1px solid rgba(0,0,0,0.2); cursor: pointer; } .color-swatch:hover { outline: 2px solid rgba(0,0,0,0.2); } .tier-label { display: inline-block; padding: 2px 6px; border-radius: 3px; background: rgba(255,255,255,0.15); } .tier-label[contenteditable="true"] { outline: none; cursor: text; } .exporting .tier-dropzone.pool { border-color: transparent; background: transparent; } </style> <script> (function() { function ready(fn) { if (document.readyState !== 'loading') fn(); else document.addEventListener('DOMContentLoaded', fn); } function contrastColor(hex) { hex = (hex || '').replace('#',''); if (hex.length === 3) hex = hex.split('').map(c => c + c).join(''); if (!/^[0-9a-fA-F]{6}$/.test(hex)) return '#fff'; var r = parseInt(hex.substr(0,2), 16); var g = parseInt(hex.substr(2,2), 16); var b = parseInt(hex.substr(4,2), 16); var yiq = ((r*299)+(g*587)+(b*114))/1000; return yiq >= 128 ? '#000' : '#fff'; } function getDragAfterElement(container, y) { const elements = [...container.querySelectorAll('.avatar-frame:not(.dragging)')]; return elements.reduce((closest, child) => { const box = child.getBoundingClientRect(); const offset = y - box.top - box.height/2; if (offset < 0 && offset > closest.offset) { return { offset: offset, element: child }; } else { return closest; } }, { offset: Number.NEGATIVE_INFINITY, element: null }).element; } function ensureCrossOrigin(img) { try { if (!img) return; if (!img.crossOrigin) img.crossOrigin = 'anonymous'; if (!img.referrerPolicy) img.referrerPolicy = 'no-referrer'; } catch(e) {} } function makeDraggable(avatar) { if (!avatar || avatar._draggableInit) return; avatar._draggableInit = true; avatar.setAttribute('draggable', 'true'); avatar.classList.add('draggable-avatar'); avatar.querySelectorAll('img').forEach(ensureCrossOrigin); avatar.addEventListener('dragstart', function(e) { avatar.classList.add('dragging'); avatar._prevParent = avatar.parentNode; e.dataTransfer.setData('text/plain', avatar.dataset.id || avatar.querySelector('.avatar-name')?.textContent || ''); e.dataTransfer.effectAllowed = 'move'; }); avatar.addEventListener('dragend', function() { avatar.classList.remove('dragging'); cleanupEmptyWrapper(avatar._prevParent); avatar._prevParent = null; }); } function initAvatars(root) { if (!root) return; const avatars = root.querySelectorAll('.avatar-frame'); avatars.forEach(function(av) { if (!av.dataset.id) { const nameEl = av.querySelector('.avatar-name'); av.dataset.name = nameEl ? nameEl.textContent.trim() : ''; } makeDraggable(av); }); } function cleanupEmptyWrapper(node) { if (!node || node.nodeType !== 1) return; if (node.classList && node.classList.contains('tier-dropzone')) return; const hasElementChild = node.querySelector('.avatar-frame'); const onlyWhitespace = !node.textContent || node.textContent.trim().length === 0; if (!hasElementChild && node.childElementCount === 0 && onlyWhitespace) { node.parentNode && node.parentNode.removeChild(node); } } function cleanupEmptyPlaceholdersIn(container) { if (!container) return; Array.from(container.children).forEach(function(child) { if (child.nodeType !== 1) return; if (child.classList.contains('avatar-frame')) return; const hasAvatarInside = !!child.querySelector('.avatar-frame'); const onlyWhitespace = !child.textContent || child.textContent.trim().length === 0; if (!hasAvatarInside && child.childElementCount === 0 && onlyWhitespace) { child.remove(); } }); } function initDropzone(zone) { if (!zone || zone._dropzoneInit) return; zone._dropzoneInit = true; zone.addEventListener('dragover', function(e) { e.preventDefault(); e.dataTransfer.dropEffect = 'move'; const afterElement = getDragAfterElement(zone, e.clientY); const dragging = document.querySelector('.avatar-frame.dragging'); if (!dragging) return; if (afterElement == null) { if (dragging.parentNode !== zone) zone.appendChild(dragging); } else { if (afterElement !== dragging) zone.insertBefore(dragging, afterElement); } }); zone.addEventListener('drop', function(e) { e.preventDefault(); e.stopPropagation(); const dragging = document.querySelector('.avatar-frame.dragging'); if (dragging) { if (dragging.parentNode !== zone) zone.appendChild(dragging); cleanupEmptyWrapper(dragging._prevParent); dragging._prevParent = null; } if (zone.classList.contains('pool')) { cleanupEmptyPlaceholdersIn(zone); } }); } function buildEditableHead(th) { const currentText = (th.childNodes[0] && th.childNodes[0].nodeType === 3) ? th.childNodes[0].nodeValue.trim() : th.textContent.trim(); const tools = th.querySelector('.tier-tools'); th.innerHTML = ''; const label = document.createElement('div'); label.className = 'tier-label'; label.setAttribute('contenteditable', 'true'); label.textContent = currentText || '未命名'; const toolsWrap = tools || (function() { const t = document.createElement('div'); t.className = 'tier-tools'; const color = document.createElement('div'); color.className = 'color-toggle'; color.title = '更改颜色'; const del = document.createElement('div'); del.className = 'delete-row'; del.textContent = '删除'; del.title = '删除该行'; t.appendChild(color); t.appendChild(del); return t; })(); th.appendChild(label); th.appendChild(toolsWrap); const initialBg = th.getAttribute('data-initial-bg') || '#555'; th.style.background = initialBg; th.style.color = contrastColor(initialBg); attachColorPalette(toolsWrap.querySelector('.color-toggle'), th); const delBtn = toolsWrap.querySelector('.delete-row'); delBtn.addEventListener('click', function() { const tr = th.closest('tr'); const dropzone = tr.querySelector('.tier-dropzone'); const pool = document.getElementById('character-pool'); Array.from(dropzone.querySelectorAll('.avatar-frame')).forEach(function(av) { pool.appendChild(av); }); tr.parentNode.removeChild(tr); }); } function attachColorPalette(toggle, th) { if (!toggle) return; const palette = document.createElement('div'); palette.className = 'color-palette'; const colors = [ '#e53935','#d81b60','#8e24aa','#5e35b1','#3949ab','#1e88e5','#039be5','#00acc1', '#00897b','#43a047','#7cb342','#c0ca33','#fdd835','#fb8c00','#f4511e','#6d4c41', '#546e7a','#9e9e9e','#000000','#ffffff' ]; colors.forEach(function(c) { const sw = document.createElement('div'); sw.className = 'color-swatch'; sw.style.background = c; sw.addEventListener('click', function() { th.style.background = c; th.style.color = contrastColor(c); palette.style.display = 'none'; }); palette.appendChild(sw); }); document.body.appendChild(palette); function placePalette() { const rect = toggle.getBoundingClientRect(); palette.style.left = (window.scrollX + rect.left) + 'px'; palette.style.top = (window.scrollY + rect.bottom + 6) + 'px'; } toggle.addEventListener('click', function(e) { e.stopPropagation(); if (palette.style.display === 'block') { palette.style.display = 'none'; } else { placePalette(); palette.style.display = 'block'; } }); document.addEventListener('click', function(e) { if (e.target === toggle || palette.contains(e.target)) return; palette.style.display = 'none'; }); window.addEventListener('scroll', function() { if (palette.style.display === 'block') placePalette(); }); window.addEventListener('resize', function() { if (palette.style.display === 'block') placePalette(); }); } function addNewRow() { const tbody = document.querySelector('#tierlist-table tbody') || document.querySelector('#tierlist-table'); const tr = document.createElement('tr'); tr.className = 'tier-row'; const th = document.createElement('th'); th.className = 'tier-head'; th.setAttribute('data-initial-bg', '#8888ff'); th.textContent = '新行'; const td = document.createElement('td'); td.className = 'tier-cell'; const dz = document.createElement('div'); dz.className = 'tier-dropzone'; dz.setAttribute('data-tier', 'CUSTOM'); td.appendChild(dz); tr.appendChild(th); tr.appendChild(td); tbody.appendChild(tr); initDropzone(dz); buildEditableHead(th); } function ensureHtml2Canvas(cb) { if (window.html2canvas) { cb(); return; } var s = document.createElement('script'); s.src = 'https://cdn.jsdelivr.net/npm/html2canvas@1.4.1/dist/html2canvas.min.js'; s.onload = cb; s.onerror = function() { alert('加载截图库失败,请检查网络或跨域策略。'); }; document.body.appendChild(s); } function downloadCanvas(canvas) { function done(blobOrUrl) { try { const link = document.createElement('a'); const isBlob = blobOrUrl instanceof Blob; const url = isBlob ? (URL.createObjectURL(blobOrUrl)) : blobOrUrl; link.href = url; link.download = 'tierlist.png'; document.body.appendChild(link); link.click(); document.body.removeChild(link); if (isBlob) setTimeout(() => URL.revokeObjectURL(url), 0); } catch (e) { const dataUrl = canvas.toDataURL('image/png'); window.open(dataUrl, '_blank'); } } if (canvas.toBlob) { canvas.toBlob(function(blob) { if (blob) done(blob); else done(canvas.toDataURL('image/png')); }, 'image/png'); } else { done(canvas.toDataURL('image/png')); } } function prepareImagesForExport(container) { if (!container) return; container.querySelectorAll('img').forEach(ensureCrossOrigin); } function savePNG() { const maker = document.getElementById('tierlist-maker'); const table = document.getElementById('tierlist-table'); if (!table) { alert('未找到要导出的表格。'); return; } maker.classList.add('exporting'); prepareImagesForExport(table); ensureHtml2Canvas(function() { html2canvas(table, { backgroundColor: null, scale: 2, useCORS: true, allowTaint: false, imageTimeout: 15000 }).then(function(canvas) { downloadCanvas(canvas); }).catch(function(err) { console.error('html2canvas 失败', err); alert('保存PNG失败:' + (err && err.message ? err.message : '未知错误')); }).finally(function() { maker.classList.remove('exporting'); }); }); } function resetAll() { const pool = document.getElementById('character-pool'); if (!pool) return; const rows = document.querySelectorAll('#tierlist-table .tier-dropzone'); rows.forEach(function(zone) { if (zone.classList.contains('pool')) return; Array.from(zone.querySelectorAll('.avatar-frame')).forEach(function(av) { pool.appendChild(av); }); cleanupEmptyPlaceholdersIn(zone); }); cleanupEmptyPlaceholdersIn(pool); } ready(function() { document.querySelectorAll('#tierlist-table .tier-head').forEach(buildEditableHead); document.querySelectorAll('.tier-dropzone').forEach(initDropzone); initAvatars(document.getElementById('character-pool')); var addBtn = document.getElementById('add-row'); if (addBtn) addBtn.addEventListener('click', addNewRow); var saveBtn = document.getElementById('save-png'); if (saveBtn) saveBtn.addEventListener('click', savePNG); (function insertResetButton() { const controls = document.querySelector('#tierlist-maker .tierlist-controls'); if (!controls || document.getElementById('reset-roles')) return; const resetBtn = document.createElement('div'); resetBtn.id = 'reset-roles'; resetBtn.className = 'btn'; resetBtn.textContent = '重置'; controls.insertBefore(resetBtn, controls.querySelector('#save-png') || null); resetBtn.addEventListener('click', resetAll); })(); const pool = document.getElementById('character-pool'); if (pool) { const obs = new MutationObserver(function(muts) { muts.forEach(function(m) { if (m.addedNodes && m.addedNodes.length) { m.addedNodes.forEach(function(n) { if (n.nodeType === 1) { if (n.classList.contains('avatar-frame')) { makeDraggable(n); } n.querySelectorAll && n.querySelectorAll('.avatar-frame').forEach(makeDraggable); // 去除初始即为空的无用占位 if (pool.contains(n)) cleanupEmptyPlaceholdersIn(pool); } }); } }); }); obs.observe(pool, { childList: true, subtree: true }); } }); })(); </script> </includeonly>
返回
微件:TierListMaker
。