|
<!DOCTYPE html> |
|
<html lang="zh-CN"> |
|
<head> |
|
<meta charset="UTF-8"> |
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
<title>生产环境矢量图形导出测试</title> |
|
<style> |
|
body { |
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; |
|
margin: 0; |
|
padding: 20px; |
|
background: #f5f5f5; |
|
} |
|
|
|
.container { |
|
max-width: 1200px; |
|
margin: 0 auto; |
|
background: white; |
|
border-radius: 8px; |
|
box-shadow: 0 2px 10px rgba(0,0,0,0.1); |
|
padding: 30px; |
|
} |
|
|
|
.header { |
|
text-align: center; |
|
margin-bottom: 40px; |
|
padding-bottom: 20px; |
|
border-bottom: 2px solid #e0e0e0; |
|
} |
|
|
|
.test-section { |
|
margin-bottom: 40px; |
|
padding: 20px; |
|
border: 1px solid #e0e0e0; |
|
border-radius: 6px; |
|
background: #fafafa; |
|
} |
|
|
|
.test-title { |
|
font-size: 18px; |
|
font-weight: 600; |
|
color: #333; |
|
margin-bottom: 15px; |
|
padding-bottom: 10px; |
|
border-bottom: 1px solid #ddd; |
|
} |
|
|
|
.vector-samples { |
|
display: grid; |
|
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); |
|
gap: 20px; |
|
margin-top: 20px; |
|
} |
|
|
|
.vector-item { |
|
background: white; |
|
border: 1px solid #ddd; |
|
border-radius: 4px; |
|
padding: 15px; |
|
text-align: center; |
|
} |
|
|
|
.vector-display { |
|
width: 100%; |
|
height: 120px; |
|
display: flex; |
|
align-items: center; |
|
justify-content: center; |
|
margin-bottom: 10px; |
|
background: #f9f9f9; |
|
border: 1px dashed #ccc; |
|
} |
|
|
|
.test-controls { |
|
margin-top: 30px; |
|
text-align: center; |
|
} |
|
|
|
.btn { |
|
background: #007bff; |
|
color: white; |
|
border: none; |
|
padding: 12px 24px; |
|
border-radius: 4px; |
|
cursor: pointer; |
|
margin: 0 10px; |
|
font-size: 14px; |
|
transition: background 0.2s; |
|
} |
|
|
|
.btn:hover { |
|
background: #0056b3; |
|
} |
|
|
|
.btn.secondary { |
|
background: #6c757d; |
|
} |
|
|
|
.btn.secondary:hover { |
|
background: #545b62; |
|
} |
|
|
|
.results { |
|
margin-top: 30px; |
|
padding: 20px; |
|
background: #f8f9fa; |
|
border-radius: 4px; |
|
border-left: 4px solid #007bff; |
|
} |
|
|
|
.result-item { |
|
margin-bottom: 10px; |
|
font-family: monospace; |
|
font-size: 12px; |
|
} |
|
|
|
.success { color: #28a745; } |
|
.error { color: #dc3545; } |
|
.warning { color: #ffc107; } |
|
.info { color: #17a2b8; } |
|
|
|
.performance-metrics { |
|
display: grid; |
|
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); |
|
gap: 15px; |
|
margin-top: 20px; |
|
} |
|
|
|
.metric-card { |
|
background: white; |
|
padding: 15px; |
|
border-radius: 4px; |
|
border: 1px solid #e0e0e0; |
|
text-align: center; |
|
} |
|
|
|
.metric-value { |
|
font-size: 24px; |
|
font-weight: bold; |
|
color: #007bff; |
|
} |
|
|
|
.metric-label { |
|
font-size: 12px; |
|
color: #666; |
|
margin-top: 5px; |
|
} |
|
</style> |
|
</head> |
|
<body> |
|
<div class="container"> |
|
<div class="header"> |
|
<h1>PPTist 生产环境矢量图形导出测试</h1> |
|
<p>测试矢量图形在生产环境下的导出功能和性能表现</p> |
|
</div> |
|
|
|
|
|
<div class="test-section"> |
|
<div class="test-title">基础SVG图形测试</div> |
|
<div class="vector-samples"> |
|
<div class="vector-item"> |
|
<div class="vector-display"> |
|
<svg width="80" height="80" xmlns="http://www.w3.org/2000/svg"> |
|
<circle cx="40" cy="40" r="30" fill="#007bff" stroke="#0056b3" stroke-width="2"/> |
|
</svg> |
|
</div> |
|
<div>圆形</div> |
|
</div> |
|
|
|
<div class="vector-item"> |
|
<div class="vector-display"> |
|
<svg width="80" height="80" xmlns="http://www.w3.org/2000/svg"> |
|
<rect x="10" y="10" width="60" height="60" fill="#28a745" stroke="#1e7e34" stroke-width="2" rx="5"/> |
|
</svg> |
|
</div> |
|
<div>矩形</div> |
|
</div> |
|
|
|
<div class="vector-item"> |
|
<div class="vector-display"> |
|
<svg width="80" height="80" xmlns="http://www.w3.org/2000/svg"> |
|
<polygon points="40,10 70,70 10,70" fill="#ffc107" stroke="#e0a800" stroke-width="2"/> |
|
</svg> |
|
</div> |
|
<div>三角形</div> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
|
|
<div class="test-section"> |
|
<div class="test-title">复杂路径图形测试</div> |
|
<div class="vector-samples"> |
|
<div class="vector-item"> |
|
<div class="vector-display"> |
|
<svg width="80" height="80" xmlns="http://www.w3.org/2000/svg"> |
|
<path d="M40,10 L70,40 L40,70 L10,40 Z" fill="#dc3545" stroke="#c82333" stroke-width="2"/> |
|
</svg> |
|
</div> |
|
<div>菱形路径</div> |
|
</div> |
|
|
|
<div class="vector-item"> |
|
<div class="vector-display"> |
|
<svg width="80" height="80" xmlns="http://www.w3.org/2000/svg"> |
|
<path d="M40,10 Q70,40 40,70 Q10,40 40,10" fill="#6f42c1" stroke="#59359a" stroke-width="2"/> |
|
</svg> |
|
</div> |
|
<div>曲线路径</div> |
|
</div> |
|
|
|
<div class="vector-item"> |
|
<div class="vector-display"> |
|
<svg width="80" height="80" xmlns="http://www.w3.org/2000/svg"> |
|
<path d="M40,15 L50,35 L70,35 L56,50 L62,70 L40,58 L18,70 L24,50 L10,35 L30,35 Z" fill="#fd7e14" stroke="#e8590c" stroke-width="1"/> |
|
</svg> |
|
</div> |
|
<div>星形路径</div> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
|
|
<div class="test-section"> |
|
<div class="test-title">特效SVG测试(生产环境优化)</div> |
|
<div class="vector-samples"> |
|
<div class="vector-item"> |
|
<div class="vector-display"> |
|
<svg width="80" height="80" xmlns="http://www.w3.org/2000/svg"> |
|
<defs> |
|
<linearGradient id="grad1" x1="0%" y1="0%" x2="100%" y2="100%"> |
|
<stop offset="0%" style="stop-color:#007bff;stop-opacity:1" /> |
|
<stop offset="100%" style="stop-color:#0056b3;stop-opacity:1" /> |
|
</linearGradient> |
|
</defs> |
|
<circle cx="40" cy="40" r="30" fill="url(#grad1)" vector-effect="non-scaling-stroke"/> |
|
</svg> |
|
</div> |
|
<div>渐变圆形</div> |
|
</div> |
|
|
|
<div class="vector-item"> |
|
<div class="vector-display"> |
|
<svg width="80" height="80" xmlns="http://www.w3.org/2000/svg"> |
|
<defs> |
|
<filter id="shadow"> |
|
<feDropShadow dx="2" dy="2" stdDeviation="2" flood-color="#000" flood-opacity="0.3"/> |
|
</filter> |
|
</defs> |
|
<rect x="15" y="15" width="50" height="50" fill="#28a745" filter="url(#shadow)" vector-effect="non-scaling-stroke"/> |
|
</svg> |
|
</div> |
|
<div>阴影矩形</div> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
|
|
<div class="test-controls"> |
|
<button class="btn" onclick="runBasicTests()">运行基础测试</button> |
|
<button class="btn" onclick="runPerformanceTests()">性能测试</button> |
|
<button class="btn" onclick="runExportTests()">导出测试</button> |
|
<button class="btn secondary" onclick="clearResults()">清除结果</button> |
|
</div> |
|
|
|
|
|
<div class="results" id="results" style="display: none;"> |
|
<h3>测试结果</h3> |
|
<div id="result-content"></div> |
|
</div> |
|
|
|
|
|
<div class="performance-metrics" id="metrics" style="display: none;"> |
|
<div class="metric-card"> |
|
<div class="metric-value" id="svg-render-time">-</div> |
|
<div class="metric-label">SVG渲染时间 (ms)</div> |
|
</div> |
|
<div class="metric-card"> |
|
<div class="metric-value" id="export-success-rate">-</div> |
|
<div class="metric-label">导出成功率 (%)</div> |
|
</div> |
|
<div class="metric-card"> |
|
<div class="metric-value" id="memory-usage">-</div> |
|
<div class="metric-label">内存使用 (MB)</div> |
|
</div> |
|
<div class="metric-card"> |
|
<div class="metric-value" id="total-tests">-</div> |
|
<div class="metric-label">总测试数</div> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
<script> |
|
|
|
let testResults = []; |
|
let performanceMetrics = { |
|
renderTimes: [], |
|
exportSuccessCount: 0, |
|
totalTests: 0 |
|
}; |
|
|
|
|
|
function detectEnvironment() { |
|
const isProduction = location.hostname !== 'localhost' && location.hostname !== '127.0.0.1'; |
|
const isHuggingface = location.hostname.includes('hf.space') || location.hostname.includes('huggingface.co'); |
|
|
|
return { |
|
isProduction, |
|
isHuggingface, |
|
userAgent: navigator.userAgent, |
|
viewport: { |
|
width: window.innerWidth, |
|
height: window.innerHeight |
|
} |
|
}; |
|
} |
|
|
|
|
|
function addResult(type, message, data = null) { |
|
const timestamp = new Date().toLocaleTimeString(); |
|
const result = { type, message, data, timestamp }; |
|
testResults.push(result); |
|
|
|
const resultContent = document.getElementById('result-content'); |
|
const resultDiv = document.createElement('div'); |
|
resultDiv.className = `result-item ${type}`; |
|
resultDiv.innerHTML = `[${timestamp}] ${message}`; |
|
|
|
if (data) { |
|
resultDiv.innerHTML += ` (${JSON.stringify(data)})`; |
|
} |
|
|
|
resultContent.appendChild(resultDiv); |
|
document.getElementById('results').style.display = 'block'; |
|
} |
|
|
|
|
|
function updateMetrics() { |
|
const avgRenderTime = performanceMetrics.renderTimes.length > 0 |
|
? (performanceMetrics.renderTimes.reduce((a, b) => a + b, 0) / performanceMetrics.renderTimes.length).toFixed(2) |
|
: '0'; |
|
|
|
const successRate = performanceMetrics.totalTests > 0 |
|
? ((performanceMetrics.exportSuccessCount / performanceMetrics.totalTests) * 100).toFixed(1) |
|
: '0'; |
|
|
|
const memoryUsage = performance.memory |
|
? (performance.memory.usedJSHeapSize / 1024 / 1024).toFixed(1) |
|
: 'N/A'; |
|
|
|
document.getElementById('svg-render-time').textContent = avgRenderTime; |
|
document.getElementById('export-success-rate').textContent = successRate; |
|
document.getElementById('memory-usage').textContent = memoryUsage; |
|
document.getElementById('total-tests').textContent = performanceMetrics.totalTests; |
|
|
|
document.getElementById('metrics').style.display = 'grid'; |
|
} |
|
|
|
|
|
async function runBasicTests() { |
|
addResult('info', '开始基础SVG测试...'); |
|
|
|
const env = detectEnvironment(); |
|
addResult('info', '环境检测完成', env); |
|
|
|
|
|
const svgElements = document.querySelectorAll('svg'); |
|
let successCount = 0; |
|
|
|
for (let i = 0; i < svgElements.length; i++) { |
|
const svg = svgElements[i]; |
|
const startTime = performance.now(); |
|
|
|
try { |
|
|
|
const serializer = new XMLSerializer(); |
|
const svgString = serializer.serializeToString(svg); |
|
|
|
|
|
const hasVectorEffect = svgString.includes('vector-effect'); |
|
const hasNamespace = svgString.includes('xmlns'); |
|
|
|
const renderTime = performance.now() - startTime; |
|
performanceMetrics.renderTimes.push(renderTime); |
|
performanceMetrics.totalTests++; |
|
|
|
if (svgString.length > 0) { |
|
successCount++; |
|
performanceMetrics.exportSuccessCount++; |
|
addResult('success', `SVG ${i + 1} 渲染成功`, { |
|
renderTime: renderTime.toFixed(2) + 'ms', |
|
hasVectorEffect, |
|
hasNamespace, |
|
size: svgString.length |
|
}); |
|
} else { |
|
addResult('error', `SVG ${i + 1} 渲染失败 - 空字符串`); |
|
} |
|
} catch (error) { |
|
performanceMetrics.totalTests++; |
|
addResult('error', `SVG ${i + 1} 渲染失败`, { error: error.message }); |
|
} |
|
} |
|
|
|
addResult('info', `基础测试完成: ${successCount}/${svgElements.length} 成功`); |
|
updateMetrics(); |
|
} |
|
|
|
|
|
async function runPerformanceTests() { |
|
addResult('info', '开始性能测试...'); |
|
|
|
const testIterations = 10; |
|
const svgElements = document.querySelectorAll('svg'); |
|
|
|
for (let iteration = 0; iteration < testIterations; iteration++) { |
|
for (let i = 0; i < svgElements.length; i++) { |
|
const svg = svgElements[i]; |
|
const startTime = performance.now(); |
|
|
|
try { |
|
|
|
const clone = svg.cloneNode(true); |
|
clone.removeAttribute('vector-effect'); |
|
|
|
const serializer = new XMLSerializer(); |
|
const svgString = serializer.serializeToString(clone); |
|
const base64 = btoa(svgString); |
|
|
|
const renderTime = performance.now() - startTime; |
|
performanceMetrics.renderTimes.push(renderTime); |
|
performanceMetrics.totalTests++; |
|
performanceMetrics.exportSuccessCount++; |
|
|
|
} catch (error) { |
|
performanceMetrics.totalTests++; |
|
addResult('warning', `性能测试迭代 ${iteration + 1}, SVG ${i + 1} 失败`, { error: error.message }); |
|
} |
|
} |
|
} |
|
|
|
addResult('success', `性能测试完成: ${testIterations} 轮迭代`); |
|
updateMetrics(); |
|
} |
|
|
|
|
|
async function runExportTests() { |
|
addResult('info', '开始导出测试...'); |
|
|
|
const testContainer = document.querySelector('.container'); |
|
|
|
try { |
|
|
|
const htmlContent = testContainer.innerHTML; |
|
const blob = new Blob([htmlContent], { type: 'text/html' }); |
|
|
|
addResult('success', 'HTML导出测试成功', { |
|
size: blob.size + ' bytes', |
|
type: blob.type |
|
}); |
|
|
|
performanceMetrics.totalTests++; |
|
performanceMetrics.exportSuccessCount++; |
|
|
|
} catch (error) { |
|
performanceMetrics.totalTests++; |
|
addResult('error', 'HTML导出测试失败', { error: error.message }); |
|
} |
|
|
|
|
|
try { |
|
const canvas = document.createElement('canvas'); |
|
const ctx = canvas.getContext('2d'); |
|
canvas.width = 800; |
|
canvas.height = 600; |
|
|
|
|
|
ctx.fillStyle = '#ffffff'; |
|
ctx.fillRect(0, 0, canvas.width, canvas.height); |
|
ctx.fillStyle = '#007bff'; |
|
ctx.fillText('导出测试', 50, 50); |
|
|
|
const dataUrl = canvas.toDataURL('image/png'); |
|
|
|
addResult('success', '图像导出测试成功', { |
|
format: 'PNG', |
|
size: dataUrl.length + ' chars' |
|
}); |
|
|
|
performanceMetrics.totalTests++; |
|
performanceMetrics.exportSuccessCount++; |
|
|
|
} catch (error) { |
|
performanceMetrics.totalTests++; |
|
addResult('error', '图像导出测试失败', { error: error.message }); |
|
} |
|
|
|
updateMetrics(); |
|
} |
|
|
|
|
|
function clearResults() { |
|
testResults = []; |
|
performanceMetrics = { |
|
renderTimes: [], |
|
exportSuccessCount: 0, |
|
totalTests: 0 |
|
}; |
|
|
|
document.getElementById('result-content').innerHTML = ''; |
|
document.getElementById('results').style.display = 'none'; |
|
document.getElementById('metrics').style.display = 'none'; |
|
} |
|
|
|
|
|
document.addEventListener('DOMContentLoaded', function() { |
|
addResult('info', 'PPTist 生产环境矢量图形导出测试页面已加载'); |
|
|
|
const env = detectEnvironment(); |
|
if (env.isProduction) { |
|
addResult('info', '检测到生产环境'); |
|
} |
|
if (env.isHuggingface) { |
|
addResult('info', '检测到Huggingface环境'); |
|
} |
|
}); |
|
</script> |
|
</body> |
|
</html> |