Re: 將製作ejcees(中國象棋打譜程式)
发表于 : 2026年 3月 15日 10:52
做好了導出svg動畫,加上了speed:
https://ejsoon.vip/wp-content/uploads/2 ... d9992.html
https://ejsoon.vip/wp-content/uploads/2 ... d9992.html
手捧一份淨土,劃分文學、外語、音樂、茶座、IT等圈子,寓意為在一個個圈子裡與你相遇,在這里圈圈和朋友們討論酷的東西
https://quanquan.space/
代码: 全选
把以下代碼轉成類名加css,包括innerHTML也寫到css裡面。 const closeBtn = document.createElement('button');
closeBtn.innerHTML = '<svg viewBox="0 0 24 24" width="22" height="22"><path fill="#fff" d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg>';
closeBtn.style.position = 'absolute';
closeBtn.style.top = '10px';
closeBtn.style.right = '10px';
closeBtn.style.background = 'transparent';
closeBtn.style.border = 'none';
closeBtn.style.cursor = 'pointer';
代码: 全选
以下是將你提供的 JavaScript 代碼完整轉換成 **類名 + CSS** 的版本(已將 `innerHTML` 的 SVG 轉換成 CSS 的 `data URL`,完全不需要 JavaScript 來設定內容與樣式):
### HTML(直接使用即可,無需 JS 建立元素)
```html
<button class="close-btn"></button>
```
### CSS(全部樣式 + SVG 都寫在這裡)
```css
.close-btn {
position: absolute;
top: 10px;
right: 10px;
width: 22px;
height: 22px;
padding: 0; /* 避免 button 預設 padding */
background-color: transparent;
background-image: url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 24 24%22 width=%2222%22 height=%2222%22%3E%3Cpath fill=%22%23fff%22 d=%22M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z%22/%3E%3C/svg%3E");
background-repeat: no-repeat;
background-position: center;
background-size: 22px 22px;
border: none;
cursor: pointer;
}
```
### 使用方式
- 把上面的 `<button class="close-btn"></button>` 放在你原本要放關閉按鈕的位置(記得它的父層要設定 `position: relative;`)。
- 直接把 CSS 複製到你的 stylesheet 裡即可。
- 完全不需要原本的 `document.createElement`、`innerHTML` 和 `style.xxx =` 這些 JavaScript 程式碼。
這樣就乾淨多了!如果你要加上 hover 效果(例如放大或變色),也可以再告訴我,我幫你補上。代码: 全选
下面是html和css,為什麼svg顯示還是會有白邊?我希望顯示時適配svg的長寬比。
<style>
.ejcees-export-modal {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background-color: rgba(0,0,0,0.85);
z-index: 777;
display: flex;
justify-content: center;
align-items: center;
}
.ejcees-export-box {
position: relative;
background-color: #333;
padding: 35px 20px 20px;
border-radius: 8px;
display: flex;
flex-direction: column;
align-items: center;
gap: 15px;
max-height: 90vh;
max-width: 90vw;
box-shadow: 0px 0px 25px rgba(0,0,0,0.5);
box-sizing: border-box;
}
.ejcees-export-preview {
width: auto;
height: 60vh;
max-width: 100%;
background-color: transparent;
display: flex;
justify-content: center;
align-items: center;
box-sizing: border-box;
}
.ejcees-export-preview svg {
display: block;
height: 100%;
aspect-ratio: 432 / 480;
background-color: #f4f4f9;
}
</style>
<div class="ejcees-export-modal">
<div class="ejcees-export-box">
<div class="ejcees-export-preview">
<svg class="ejceespbanimate" viewBox="0 0 432 480" preserveAspectRatio="xMidYMid meet" id="etani" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" width="480" height="432" rfm="repeat">
...
</svg>
</div>
</div>
</div>
代码: 全选
**Modification 1: Add STORAGE_KEY constant**
(Place immediately after the existing variable declarations for undoStack/redoStack at the top of the `<script>` tag)
```js
let undoStack = [];
let redoStack = [];
// Persistent storage key for undo/redo stack (survives page reloads)
const STORAGE_KEY = 'ejceesGameState';
```
**Modification 2: Replace the entire `saveStateToUndo` function**
(Find the original `saveStateToUndo` and replace it completely)
```js
function saveStateToUndo() {
undoStack.push(cloneGameState());
if (undoStack.length > 36) undoStack.shift(); // limit history size
redoStack = []; // clear redo on new action
// Persist the entire undo/redo stack to localStorage
localStorage.setItem(STORAGE_KEY, JSON.stringify({
undoStack: undoStack,
redoStack: redoStack
}));
}
```
**Modification 3: Replace the entire `undo` function**
(Find the original `undo` and replace it completely)
```js
function undo() {
if (undoStack.length === 1) return;
const previous = undoStack.pop();
redoStack.push(previous);
restoreState(undoStack[undoStack.length - 1]);
// Persist changes to localStorage after undo
localStorage.setItem(STORAGE_KEY, JSON.stringify({
undoStack: undoStack,
redoStack: redoStack
}));
}
```
**Modification 4: Replace the entire `redo` function**
(Find the original `redo` and replace it completely)
```js
function redo() {
if (redoStack.length === 0) return;
const next = redoStack.pop();
undoStack.push(next);
restoreState(next);
// Persist changes to localStorage after redo
localStorage.setItem(STORAGE_KEY, JSON.stringify({
undoStack: undoStack,
redoStack: redoStack
}));
}
```
**Modification 5: Add localStorage loading logic at the start of `DOMContentLoaded`**
(Insert right after `document.addEventListener('DOMContentLoaded', () => {`)
```js
// First load persisted state from localStorage if available.
// This restores the exact game tree, branch path, step index, and undo/redo stack.
const savedData = localStorage.getItem(STORAGE_KEY);
let loadedFromStorage = false;
if (savedData) {
try {
const parsed = JSON.parse(savedData);
if (parsed.undoStack && parsed.undoStack.length > 0) {
undoStack = parsed.undoStack;
redoStack = parsed.redoStack || [];
// Restore the most recent state (this also calls loadFEN, render, etc.)
restoreState(undoStack[undoStack.length - 1]);
loadedFromStorage = true;
}
} catch (e) {
console.warn('Failed to restore from localStorage:', e);
localStorage.removeItem(STORAGE_KEY);
}
}
```
**Modification 6: Wrap the original boot code with `if (!loadedFromStorage)`**
(Find the block starting with `// --- Boot the App ---` and wrap the entire original initialization code)
```js
// --- Boot the App ---
if (!loadedFromStorage) {
loadFEN(INITIAL_FEN);
historyFEN = {
fen: INITIAL_FEN,
move: null,
lastMove: null,
c: "",
v: []
};
currentBranch = [];
currentStepIndex = 0;
stepSlider.max = 0;
stepSlider.value = 0;
applyLastMoveVisuals(null);
highlightActiveStep(0);
renderNoteUI();
// Save state (this also saves to localStorage)
saveStateToUndo();
// Initial highlight update after boot
updateToolHighlights();
}
```
These are the **only** changes required. The rest of the code remains untouched. The game now automatically saves the undo/redo stack on every action and restores the exact previous session when the page is reopened.