|
|
| 第95行: |
第95行: |
| <!-- {blockquote:.is-info} --> | | <!-- {blockquote:.is-info} --> |
| #### 示例 | | #### 示例 |
| <!-- 弥恩世界 - 交互式意识形态坐标图 -->
| |
| <!-- 将此代码块直接复制到您的编辑器中即可使用 -->
| |
|
| |
|
| <!-- 第一部分:坐标图容器与控件 -->
| |
| <div class="ideology-chart-container" style="margin: 2rem 0; padding: 1rem; background: #f8f9fa; border-radius: 8px; border: 1px solid #dee2e6;">
| |
| <h3 style="color: #8B7355; border-bottom: 2px solid #8B7355; padding-bottom: 0.5rem;">弥恩世界意识形态动态坐标图</h3>
| |
| <p style="color: #666; font-size: 0.9rem; margin-bottom: 1rem;">
| |
| 拖拽蓝色定位点可调整其位置。点击下方表格中的“定位”按钮可高亮对应点。横轴(X):<strong>激进变革(左)← → 传统守序(右)</strong>;纵轴(Y):<strong>主动驾驭(上)← → 敬畏顺从(下)</strong>
| |
| </p>
| |
|
| |
| <!-- 坐标图画布 -->
| |
| <div class="chart-canvas" style="position: relative; width: 100%; height: 500px; background: white; border: 2px solid #333; border-radius: 4px; overflow: hidden;">
| |
| <!-- 坐标轴与网格线 -->
| |
| <div class="gridline" style="position: absolute; left: 50%; top: 0; width: 1px; height: 100%; background: rgba(0,0,0,0.1); transform: translateX(-50%);"></div> <!-- 垂直中线 -->
| |
| <div class="gridline" style="position: absolute; left: 0; top: 50%; width: 100%; height: 1px; background: rgba(0,0,0,0.1); transform: translateY(-50%);"></div> <!-- 水平中线 -->
| |
| <!-- 坐标轴标签 -->
| |
| <div style="position: absolute; left: 10px; top: 10px; color: #CC0000; font-weight: bold;">激进变革</div>
| |
| <div style="position: absolute; right: 10px; top: 10px; color: #2E4D2B; font-weight: bold;">传统守序</div>
| |
| <div style="position: absolute; left: 10px; top: 10px; color: #4682B4; font-weight: bold; transform: translateY(20px);">主动驾驭</div>
| |
| <div style="position: absolute; left: 10px; bottom: 10px; color: #B8860B; font-weight: bold;">敬畏顺从</div>
| |
|
| |
| <!-- 动态定位点将在此生成 -->
| |
| <div id="chart-points-container"></div>
| |
| </div>
| |
|
| |
| <!-- 坐标显示与控制面板 -->
| |
| <div style="margin-top: 1rem; display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 1rem;">
| |
| <div>
| |
| <strong>当前选中:</strong><span id="selected-point-name">无</span>
| |
| <span id="selected-point-coords" style="margin-left: 1rem; color: #666; font-family: monospace;">(X: -, Y: -)</span>
| |
| </div>
| |
| <div>
| |
| <button onclick="resetAllPoints()" style="padding: 0.4rem 0.8rem; background: #6c757d; color: white; border: none; border-radius: 4px; cursor: pointer;">重置所有点到默认位置</button>
| |
| <button onclick="exportCoordinates()" style="margin-left: 0.5rem; padding: 0.4rem 0.8rem; background: #28a745; color: white; border: none; border-radius: 4px; cursor: pointer;">导出当前坐标数据</button>
| |
| </div>
| |
| </div>
| |
| </div>
| |
|
| |
| <!-- 第二部分:可编辑的实体数据表格 -->
| |
| <div style="margin: 2rem 0; overflow-x: auto;">
| |
| <h4 style="color: #8B7355;">意识形态实体坐标管理表</h4>
| |
| <table id="ideology-table" style="width: 100%; border-collapse: collapse; font-size: 0.9rem; margin-top: 1rem;">
| |
| <thead>
| |
| <tr style="background-color: #e9ecef;">
| |
| <th style="padding: 0.75rem; border: 1px solid #dee2e6; text-align: left;">实体</th>
| |
| <th style="padding: 0.75rem; border: 1px solid #dee2e6; text-align: left;">意识形态标签</th>
| |
| <th style="padding: 0.75rem; border: 1px solid #dee2e6; text-align: center;">当前坐标</th>
| |
| <th style="padding: 0.75rem; border: 1px solid #dee2e6; text-align: center;">默认坐标</th>
| |
| <th style="padding: 0.75rem; border: 1px solid #dee2e6; text-align: center;">操作</th>
| |
| </tr>
| |
| </thead>
| |
| <tbody>
| |
| <!-- 每一行对应一个实体,可以随意添加 -->
| |
| <tr id="row-1">
| |
| <td style="padding: 0.75rem; border: 1px solid #dee2e6;"><strong>[[赤环学会]]</strong></td>
| |
| <td style="padding: 0.75rem; border: 1px solid #dee2e6; color: #CC0000;">革命理性主义</td>
| |
| <td class="coord-cell" style="padding: 0.75rem; border: 1px solid #dee2e6; text-align: center; font-family: monospace;">0.15, 0.85</td>
| |
| <td style="padding: 0.75rem; border: 1px solid #dee2e6; text-align: center; font-family: monospace; color: #999;">0.15, 0.85</td>
| |
| <td style="padding: 0.75rem; border: 1px solid #dee2e6; text-align: center;">
| |
| <button onclick="focusPoint('point-1')" style="padding: 0.25rem 0.5rem; background: #007bff; color: white; border: none; border-radius: 3px; cursor: pointer; margin-right: 0.25rem;">定位</button>
| |
| <button onclick="resetPoint('point-1', 0.15, 0.85)" style="padding: 0.25rem 0.5rem; background: #ffc107; color: black; border: none; border-radius: 3px; cursor: pointer;">重置</button>
| |
| </td>
| |
| </tr>
| |
| <tr id="row-2">
| |
| <td style="padding: 0.75rem; border: 1px solid #dee2e6;"><strong>[[铸铁公约]]</strong></td>
| |
| <td style="padding: 0.75rem; border: 1px solid #dee2e6; color: #4682B4;">技术威权主义</td>
| |
| <td class="coord-cell" style="padding: 0.75rem; border: 1px solid #dee2e6; text-align: center; font-family: monospace;">0.85, 0.80</td>
| |
| <td style="padding: 0.75rem; border: 1px solid #dee2e6; text-align: center; font-family: monospace; color: #999;">0.85, 0.80</td>
| |
| <td style="padding: 0.75rem; border: 1px solid #dee2e6; text-align: center;">
| |
| <button onclick="focusPoint('point-2')" style="padding: 0.25rem 0.5rem; background: #007bff; color: white; border: none; border-radius: 3px; cursor: pointer; margin-right: 0.25rem;">定位</button>
| |
| <button onclick="resetPoint('point-2', 0.85, 0.80)" style="padding: 0.25rem 0.5rem; background: #ffc107; color: black; border: none; border-radius: 3px; cursor: pointer;">重置</button>
| |
| </td>
| |
| </tr>
| |
| <tr id="row-3">
| |
| <td style="padding: 0.75rem; border: 1px solid #dee2e6;"><strong>[[林语会]]</strong></td>
| |
| <td style="padding: 0.75rem; border: 1px solid #dee2e6; color: #B8860B;">灵性公社主义</td>
| |
| <td class="coord-cell" style="padding: 0.75rem; border: 1px solid #dee2e6; text-align: center; font-family: monospace;">0.20, 0.20</td>
| |
| <td style="padding: 0.75rem; border: 1px solid #dee2e6; text-align: center; font-family: monospace; color: #999;">0.20, 0.20</td>
| |
| <td style="padding: 0.75rem; border: 1px solid #dee2e6; text-align: center;">
| |
| <button onclick="focusPoint('point-3')" style="padding: 0.25rem 0.5rem; background: #007bff; color: white; border: none; border-radius: 3px; cursor: pointer; margin-right: 0.25rem;">定位</button>
| |
| <button onclick="resetPoint('point-3', 0.20, 0.20)" style="padding: 0.25rem 0.5rem; background: #ffc107; color: black; border: none; border-radius: 3px; cursor: pointer;">重置</button>
| |
| </td>
| |
| </tr>
| |
| <!-- 您可以直接复制上面的行,修改以下变量来添加新实体:
| |
| - 修改所有 id 中的数字(如 row-4, point-4)
| |
| - 修改实体名称和意识形态标签
| |
| - 修改默认坐标(两次出现)
| |
| - 修改按钮函数中的参数('point-4', x, y)
| |
| -->
| |
| </tbody>
| |
| </table>
| |
| <p style="color: #666; font-size: 0.85rem; margin-top: 0.5rem;">提示:要添加新实体,请复制一行并修改所有相关数据。坐标范围:0.0 到 1.0。</p>
| |
| </div>
| |
|
| |
| <!-- 第三部分:核心交互脚本 -->
| |
| <script>
| |
| // 1. 实体数据定义 (可以在这里添加新实体)
| |
| const entities = [
| |
| {id: 'point-1', name: '[[赤环学会]]', color: '#CC0000', defaultX: 0.15, defaultY: 0.85, rowId: 'row-1'},
| |
| {id: 'point-2', name: '[[铸铁公约]]', color: '#4682B4', defaultX: 0.85, defaultY: 0.80, rowId: 'row-2'},
| |
| {id: 'point-3', name: '[[林语会]]', color: '#B8860B', defaultX: 0.20, defaultY: 0.20, rowId: 'row-3'}
| |
| // 添加新实体示例:
| |
| // ,{id: 'point-4', name: '[[您的实体]]', color: '#颜色代码', defaultX: 0.5, defaultY: 0.5, rowId: 'row-4'}
| |
| ];
| |
|
| |
| // 2. 初始化所有定位点
| |
| function initPoints() {
| |
| const container = document.getElementById('chart-points-container');
| |
| container.innerHTML = '';
| |
|
| |
| entities.forEach(entity => {
| |
| // 从表格中读取当前坐标(如果已经调整过)
| |
| const coordCell = document.querySelector(`#${entity.rowId} .coord-cell`);
| |
| let currentX = entity.defaultX, currentY = entity.defaultY;
| |
| if (coordCell && coordCell.textContent) {
| |
| const parts = coordCell.textContent.split(',').map(s => parseFloat(s.trim()));
| |
| if (parts.length === 2 && !isNaN(parts[0]) && !isNaN(parts[1])) {
| |
| currentX = parts[0];
| |
| currentY = parts[1];
| |
| }
| |
| }
| |
|
| |
| // 创建定位点元素
| |
| const point = document.createElement('div');
| |
| point.id = entity.id;
| |
| point.className = 'chart-point';
| |
| point.style.position = 'absolute';
| |
| point.style.width = '16px';
| |
| point.style.height = '16px';
| |
| point.style.backgroundColor = entity.color;
| |
| point.style.border = '2px solid white';
| |
| point.style.borderRadius = '50%';
| |
| point.style.cursor = 'move';
| |
| point.style.boxShadow = '0 2px 4px rgba(0,0,0,0.2)';
| |
| point.style.zIndex = '10';
| |
| point.style.transform = 'translate(-50%, -50%)';
| |
|
| |
| // 计算位置(百分比)
| |
| point.style.left = `${currentX * 100}%`;
| |
| point.style.top = `${(1 - currentY) * 100}%`; // 反转Y轴,使0在上,1在下
| |
|
| |
| // 添加悬停提示
| |
| point.title = `${entity.name} (${currentX.toFixed(2)}, ${currentY.toFixed(2)})`;
| |
|
| |
| // 添加拖拽功能
| |
| makeDraggable(point, entity);
| |
|
| |
| // 添加点击事件
| |
| point.addEventListener('click', function(e) {
| |
| e.stopPropagation();
| |
| updateSelectedPoint(entity.name, currentX, currentY);
| |
| highlightPoint(entity.id);
| |
| highlightRow(entity.rowId);
| |
| });
| |
|
| |
| container.appendChild(point);
| |
| });
| |
| }
| |
|
| |
| // 3. 拖拽功能实现
| |
| function makeDraggable(element, entity) {
| |
| let isDragging = false;
| |
| let offsetX, offsetY;
| |
| const container = element.parentElement;
| |
|
| |
| element.addEventListener('mousedown', startDrag);
| |
|
| |
| function startDrag(e) {
| |
| isDragging = true;
| |
| const rect = container.getBoundingClientRect();
| |
| const pointRect = element.getBoundingClientRect();
| |
|
| |
| // 计算鼠标相对于点中心的位置
| |
| offsetX = e.clientX - pointRect.left;
| |
| offsetY = e.clientY - pointRect.top;
| |
|
| |
| document.addEventListener('mousemove', drag);
| |
| document.addEventListener('mouseup', stopDrag);
| |
|
| |
| e.preventDefault();
| |
| updateSelectedPoint(entity.name, 0, 0);
| |
| highlightPoint(entity.id);
| |
| highlightRow(entity.rowId);
| |
| }
| |
|
| |
| function drag(e) {
| |
| if (!isDragging) return;
| |
|
| |
| const rect = container.getBoundingClientRect();
| |
|
| |
| // 计算新位置(限制在容器内)
| |
| let newLeft = e.clientX - rect.left - offsetX;
| |
| let newTop = e.clientY - rect.top - offsetY;
| |
|
| |
| newLeft = Math.max(0, Math.min(newLeft, rect.width));
| |
| newTop = Math.max(0, Math.min(newTop, rect.height));
| |
|
| |
| // 转换为坐标值 (0-1)
| |
| const x = newLeft / rect.width;
| |
| const y = 1 - (newTop / rect.height); // 反转Y轴
| |
|
| |
| // 更新点位置
| |
| element.style.left = `${x * 100}%`;
| |
| element.style.top = `${(1 - y) * 100}%`;
| |
|
| |
| // 更新表格和提示
| |
| updateTableCoordinates(entity.rowId, x, y);
| |
| element.title = `${entity.name} (${x.toFixed(2)}, ${y.toFixed(2)})`;
| |
| updateSelectedPoint(entity.name, x, y);
| |
| }
| |
|
| |
| function stopDrag() {
| |
| isDragging = false;
| |
| document.removeEventListener('mousemove', drag);
| |
| document.removeEventListener('mouseup', stopDrag);
| |
| }
| |
| }
| |
|
| |
| // 4. 辅助函数
| |
| function updateTableCoordinates(rowId, x, y) {
| |
| const coordCell = document.querySelector(`#${rowId} .coord-cell`);
| |
| if (coordCell) {
| |
| coordCell.textContent = `${x.toFixed(2)}, ${y.toFixed(2)}`;
| |
| }
| |
| }
| |
|
| |
| function updateSelectedPoint(name, x, y) {
| |
| document.getElementById('selected-point-name').textContent = name;
| |
| document.getElementById('selected-point-coords').textContent = `(X: ${x.toFixed(2)}, Y: ${y.toFixed(2)})`;
| |
| }
| |
|
| |
| function highlightPoint(pointId) {
| |
| // 移除所有高亮
| |
| document.querySelectorAll('.chart-point').forEach(p => {
| |
| p.style.boxShadow = '0 2px 4px rgba(0,0,0,0.2)';
| |
| p.style.transform = 'translate(-50%, -50%)';
| |
| });
| |
|
| |
| // 高亮选中的点
| |
| const point = document.getElementById(pointId);
| |
| if (point) {
| |
| point.style.boxShadow = '0 0 0 3px rgba(0,123,255,0.5), 0 2px 8px rgba(0,0,0,0.3)';
| |
| point.style.transform = 'translate(-50%, -50%) scale(1.2)';
| |
| point.style.zIndex = '100';
| |
| }
| |
| }
| |
|
| |
| function highlightRow(rowId) {
| |
| // 移除所有行高亮
| |
| document.querySelectorAll('#ideology-table tbody tr').forEach(row => {
| |
| row.style.backgroundColor = '';
| |
| });
| |
|
| |
| // 高亮选中的行
| |
| const row = document.getElementById(rowId);
| |
| if (row) {
| |
| row.style.backgroundColor = 'rgba(0,123,255,0.1)';
| |
| }
| |
| }
| |
|
| |
| function focusPoint(pointId) {
| |
| const entity = entities.find(e => e.id === pointId);
| |
| if (entity) {
| |
| const coordCell = document.querySelector(`#${entity.rowId} .coord-cell`);
| |
| if (coordCell && coordCell.textContent) {
| |
| const parts = coordCell.textContent.split(',').map(s => parseFloat(s.trim()));
| |
| if (parts.length === 2) {
| |
| updateSelectedPoint(entity.name, parts[0], parts[1]);
| |
| }
| |
| }
| |
| highlightPoint(pointId);
| |
| highlightRow(entity.rowId);
| |
| }
| |
| }
| |
|
| |
| function resetPoint(pointId, defaultX, defaultY) {
| |
| const entity = entities.find(e => e.id === pointId);
| |
| if (!entity) return;
| |
|
| |
| // 更新表格
| |
| updateTableCoordinates(entity.rowId, defaultX, defaultY);
| |
|
| |
| // 重新初始化点(会从表格读取新坐标)
| |
| initPoints();
| |
|
| |
| // 更新选中显示
| |
| updateSelectedPoint(entity.name, defaultX, defaultY);
| |
| highlightPoint(pointId);
| |
| highlightRow(entity.rowId);
| |
| }
| |
|
| |
| function resetAllPoints() {
| |
| if (confirm('确定要重置所有点到默认位置吗?')) {
| |
| entities.forEach(entity => {
| |
| updateTableCoordinates(entity.rowId, entity.defaultX, entity.defaultY);
| |
| });
| |
| initPoints();
| |
| updateSelectedPoint('无', 0, 0);
| |
| document.querySelectorAll('#ideology-table tbody tr').forEach(row => {
| |
| row.style.backgroundColor = '';
| |
| });
| |
| }
| |
| }
| |
|
| |
| function exportCoordinates() {
| |
| let exportText = "弥恩意识形态坐标数据\n====================\n\n";
| |
| entities.forEach(entity => {
| |
| const coordCell = document.querySelector(`#${entity.rowId} .coord-cell`);
| |
| if (coordCell) {
| |
| exportText += `${entity.name}: ${coordCell.textContent}\n`;
| |
| }
| |
| });
| |
| exportText += `\n导出时间: ${new Date().toLocaleString()}`;
| |
|
| |
| // 复制到剪贴板(简单方案)
| |
| const textArea = document.createElement('textarea');
| |
| textArea.value = exportText;
| |
| document.body.appendChild(textArea);
| |
| textArea.select();
| |
| try {
| |
| document.execCommand('copy');
| |
| alert('坐标数据已复制到剪贴板!\n\n' + exportText);
| |
| } catch (err) {
| |
| alert('无法自动复制,请手动复制以下内容:\n\n' + exportText);
| |
| }
| |
| document.body.removeChild(textArea);
| |
| }
| |
|
| |
| // 5. 页面加载完成后初始化
| |
| document.addEventListener('DOMContentLoaded', function() {
| |
| initPoints();
| |
| });
| |
| </script>
| |
|
| |
| <!-- 第四部分:使用说明(可折叠) -->
| |
| <details style="margin-top: 2rem; padding: 1rem; background: #f1f3f4; border-radius: 8px;">
| |
| <summary style="font-weight: bold; color: #8B7355; cursor: pointer;">📘 使用说明与扩展指南</summary>
| |
| <div style="margin-top: 1rem; line-height: 1.6; font-size: 0.9rem;">
| |
| <h4>核心功能</h4>
| |
| <ul>
| |
| <li><strong>拖拽定位</strong>:直接在坐标图上拖拽蓝色圆点,实时调整其位置。</li>
| |
| <li><strong>表格联动</strong>:点击表格中的“定位”按钮,坐标图上对应的点会高亮显示。</li>
| |
| <li><strong>坐标管理</strong>:表格中的坐标会随拖拽自动更新,支持单个重置和全部重置。</li>
| |
| <li><strong>数据导出</strong>:点击“导出当前坐标数据”可将所有坐标复制到剪贴板。</li>
| |
| </ul>
| |
|
| |
| <h4>如何添加新实体(势力/组织)</h4>
| |
| <ol>
| |
| <li>在表格部分找到注释处,复制一行表格代码,例如复制 <code><tr id="row-3">...</tr></code>。</li>
| |
| <li>将新行的所有数字递增(如 <code>row-4</code>、<code>point-4</code>)。</li>
| |
| <li>修改实体名称、意识形态标签(确保使用正确的<span data-tooltip="请严格遵守色码表">颜色代码</span>)。</li>
| |
| <li>设置默认坐标(两个位置)。</li>
| |
| <li>在 JavaScript 部分的 <code>entities</code> 数组中添加一行新数据,格式参照现有条目。</li>
| |
| </ol>
| |
|
| |
| <h4>如何与世界观整合</h4>
| |
| <ul>
| |
| <li>此坐标图可以放置在您的 <span style="color: #8B7355;">[[世界观设定]]</span> 核心页面。</li>
| |
| <li>每个实体名称都使用了 <code>[[内部链接]]</code> 语法,确保点击可跳转到对应页面。</li>
| |
| <li>导出的坐标数据可以用于 <span style="color: #8B7355;">[[叙事记录]]</span>,记录意识形态的演变。</li>
| |
| <li>鼓励在实体描述页面引用其坐标位置,例如:“根据意识形态坐标图,本组织位于 <strong>(0.35, 0.60)</strong>,属于 <span style="color: #FF7F50;">渐进改良主义</span> 象限。”</li>
| |
| </ul>
| |
|
| |
| <p style="margin-top: 1rem; padding: 0.75rem; background: #e7f4e4; border-left: 4px solid #28a745;">
| |
| <strong>提示:</strong> 此工具完全基于标准 HTML/CSS/JavaScript,兼容绝大多数支持自定义 HTML 的 Wiki 平台和编辑器。如果遇到问题,请确保您的平台允许执行内联脚本。
| |
| </p>
| |
| </div>
| |
| </details>
| |