一,當保存時,如果不是動畫,則文件名為ejsolid_static_yyyymmdd_hhiiss.svg,如果是動畫則把static換成animate。日期和時間要用new Date()。
二,增加mini模式,div.ejsolid將寫有json數據,把它作為data傳入。本模式只顯示div#ejs-svg-container,把兩個checkbox選項絕對定位至它的左上角並改小。
三,在ejs-upload-trigger的右方新增一個download data按鈕,當點擊時將下載一個json文件,文件名為ejsolid_data_yyyymmdd_hhiiss.json。包含設置面板中的全部數據,將用於mini模式。
四,當頁面刷新時,js要把設置面板設的每一個輸入框設為初始值。
只需給出所要修改的地方,所有的代碼和注釋都要使用英文。
gemini pro你好:
代码: 全选
以下是針對您提出的四項改進要求的具體代碼修改。所有修改細節、程式碼與註解均已轉換為英文。
### 1. 新增時間戳記工具函式與修正 SVG 儲存檔名命名邏輯
在類別中新增一個用來格式化時間戳記的輔助方法 `getTimestamp()`,並修改原有儲存按鈕的點擊監聽事件。
**在類別中新增輔助方法 (Add helper method inside class):**
```javascript
/**
* Generates a formatted timestamp string (yyyymmdd_hhiiss) using current Date.
* @returns {string} Formatted timestamp.
*/
getTimestamp() {
const now = new Date();
const pad = n => String(n).padStart(2, '0');
return `${now.getFullYear()}${pad(now.getMonth() + 1)}${pad(now.getDate())}_` +
`${pad(now.getHours())}${pad(now.getMinutes())}${pad(now.getSeconds())}`;
}
```
**修改 `bindEvents()` 中負責儲存 SVG 的部分 (Update SVG save logic inside `bindEvents()`):**
```javascript
// Update the filename generation logic during SVG export
this.dom.saveBtn.onclick = () => {
if (!this.state.lastSvg) return;
const isAnim = this.dom.animToggle.checked;
const filename = `ejsolid_${isAnim ? 'animate' : 'static'}_${this.getTimestamp()}.svg`;
const blob = new Blob([this.state.lastSvg], { type: 'image/svg+xml' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename;
a.click();
URL.revokeObjectURL(url);
};
```
---
### 2. 擴充結構以支援 `mini` 模式與對應的精簡型 CSS 樣式
在構造函數中先備份原始的 JSON 文本,並在 `renderDOM()` 中判定是否載入 `mini` 模式的 DOM 佈局。這能隱藏不必要的側邊欄,僅保留 SVG 區塊,並將縮小版的控制項絕對定位至左上角。
**修改 `constructor(containerSelector)` 以暫存原始 JSON (Capture raw JSON string):**
```javascript
// Add rawJsonData to state before renderDOM clears text content
this.state = {
rotMatrix: [1, 0, 0, 0, 1, 0, 0, 0, 1],
lastSvg: '',
isDragging: false,
lastX: 0,
lastY: 0,
objData: `v 0.0 0.0 1.077364...`, // default raw fallback
parsedModel: null,
rawJsonData: this.container.textContent.trim() // Cache the config JSON
};
```
**在 `injectCSS()` 結尾追加樣式 (Append mini mode CSS into `injectCSS()`):**
```javascript
// Style configurations for the absolute-positioned mini controls overlay
styleSheet.innerText += `
.ejs-mini-controls { position: absolute; top: 8px; left: 8px; z-index: 20; display: flex; gap: 6px; background: rgba(255, 255, 255, 0.75); padding: 4px 6px; border-radius: 4px; box-shadow: 0 1px 3px rgba(0,0,0,0.15); }
.ejs-mini-controls label { font-size: 10px; font-family: sans-serif; display: flex; align-items: center; gap: 4px; cursor: pointer; }
.ejs-mini-controls input[type="checkbox"] { width: 28px !important; height: 16px !important; }
.ejs-mini-controls input[type="checkbox"]::after { width: 12px !important; height: 12px !important; top: 2px !important; left: 2px !important; }
.ejs-mini-controls input[type="checkbox"]:checked::after { transform: translateX(12px) !important; }
`;
```
**修改 `renderDOM()` 邏輯 (Conditional layout layout inside `renderDOM()`):**
```javascript
renderDOM() {
if (this.mode === 'mini') {
// Mini mode: render only the SVG container and small overlay checkboxes
this.container.innerHTML = `
<div class="ejsolid-mini-container" style="position: relative; display: inline-block;">
<div class="ejs-mini-controls">
<label><input type="checkbox" class="ejs-perspective" /> Persp</label>
<label><input type="checkbox" class="ejs-anim-toggle" /> Anim</label>
</div>
<div id="ejs-svg-container"></div>
<div style="display: none;">
<input type="number" class="ejs-canvas-size" value="480"/>
<input type="number" class="ejs-content-size" value="360"/>
<input type="number" class="ejs-opacity" value="1"/>
<input type="number" class="ejs-stroke-width" value="1"/>
<input type="color" class="ejs-stroke-color" value="#000000"/>
<input type="number" class="ejs-anim-time" value="7"/>
<input type="number" class="ejs-anim-angle" value="0"/>
<input type="number" class="ejs-frame-int" value="0.25"/>
<button type="button" class="ejs-upload-trigger"></button>
<input type="file" class="ejs-file-input" />
<button type="button" class="ejs-save-svg"></button>
</div>
</div>
`;
} else {
// Main mode: standard control panel layout ...
// (Keep existing sidebar layout here)
}
}
```
---
### 3. 新增下載設定參數 JSON 資料按鈕 (Download Data)
在控制台新增按鈕,用於打包設定面板狀態及當前 3D 模型數據至一個外部 JSON 檔中。
**在 `renderDOM()` 中新增按鈕佈局 (Add Download Data button next to upload trigger):**
```javascript
// Inside Main Mode layout template string:
`<h2>Raw Data (${this.mode})</h2>
<div class="ejsolid-control-group">
<input type="file" class="ejs-file-input" accept=".obj" style="display: none" />
<button type="button" class="ejs-upload-trigger">Choose OBJ File</button>
<button type="button" class="ejs-download-data" style="margin-left: 8px;">Download Data</button>
</div>`
```
**在 `cacheDOM()` 綁定此按鈕 (Cache reference inside `cacheDOM()`):**
```javascript
this.dom.downloadDataBtn = this.container.querySelector('.ejs-download-data');
```
**在 `bindEvents()` 中新增點擊下載邏輯 (Add click handler inside `bindEvents()`):**
```javascript
// Set up download event listener for the aggregated JSON configuration
if (this.dom.downloadDataBtn) {
this.dom.downloadDataBtn.onclick = () => {
const configData = {
objData: this.state.objData,
canvasSize: this.dom.canvasNum.value,
contentSize: this.dom.contentNum.value,
opacity: this.dom.opacityNum.value,
strokeWidth: this.dom.strokeWidthNum.value,
strokeColor: this.dom.strokeColorPicker.value,
perspective: this.dom.perspective.checked,
animate: this.dom.animToggle.checked,
animTime: this.dom.animTime.value,
animAngle: this.dom.animAngle.value,
frameInt: this.dom.frameInt.value,
colors: {}
};
// Export polygon face side colors map
this.config.sides.forEach(s => {
const el = this.container.querySelector(`.hex-${s}`);
if (el) configData.colors[s] = el.value;
});
const blob = new Blob([JSON.stringify(configData, null, 2)], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `ejsolid_data_${this.getTimestamp()}.json`;
a.click();
URL.revokeObjectURL(url);
};
}
```
---
### 4. 重新整理或初始化時重設輸入框與面板預設值
改寫 `initApp()` 生命週期方法,讓主模式在載入時自動將所有欄位初始化為指定初始值;若為 Mini 模式,則直接解析傳入的 JSON 字串。
**重寫 `initApp()` 方法 (Overwrite `initApp()` for default setups):**
```javascript
/**
* Initializes the application state, ensures inputs reset to baseline values,
* or parses internal JSON configuration if loaded under mini mode.
*/
initApp() {
if (this.mode === 'mini') {
try {
const jsonData = JSON.parse(this.state.rawJsonData || "{}");
if (jsonData.objData) this.state.objData = jsonData.objData;
if (jsonData.canvasSize) this.dom.canvasNum.value = jsonData.canvasSize;
if (jsonData.contentSize) this.dom.contentNum.value = jsonData.contentSize;
if (jsonData.opacity) this.dom.opacityNum.value = jsonData.opacity;
if (jsonData.strokeWidth) this.dom.strokeWidthNum.value = jsonData.strokeWidth;
if (jsonData.strokeColor) this.dom.strokeColorPicker.value = jsonData.strokeColor;
if (jsonData.perspective !== undefined) this.dom.perspective.checked = jsonData.perspective;
if (jsonData.animate !== undefined) this.dom.animToggle.checked = jsonData.animate;
if (jsonData.animTime) this.dom.animTime.value = jsonData.animTime;
if (jsonData.animAngle) this.dom.animAngle.value = jsonData.animAngle;
if (jsonData.frameInt) this.dom.frameInt.value = jsonData.frameInt;
if (jsonData.colors) {
Object.keys(jsonData.colors).forEach(s => {
this.config.defaultColors[s] = jsonData.colors[s];
});
}
} catch (e) {
console.error("EjSolid: Failed to process mini-mode inline configuration.", e);
}
} else {
// Forcefully assign predefined default values to form controls on every page load
this.dom.canvasNum.value = 480;
this.dom.contentNum.value = 360;
this.dom.opacityNum.value = 1.0;
this.dom.strokeWidthNum.value = 1.0;
this.dom.strokeColorPicker.value = '#000000';
this.dom.perspective.checked = false;
this.dom.animToggle.checked = false;
this.dom.animTime.value = 7.0;
this.dom.animAngle.value = 0;
this.dom.frameInt.value = 0.25;
this.config.sides.forEach(s => {
const el = this.container.querySelector(`.hex-${s}`);
if (el) el.value = this.config.defaultColors[s];
});
}
// Erase stale models and invoke initial frame rendering
this.state.parsedModel = null;
this.draw();
}
```