perf(CustomGameModal): optimize difficulty map rendering with caching

This commit is contained in:
2026-02-11 04:50:13 +01:00
parent 43822d03ac
commit a264ac75e3

View File

@@ -14,6 +14,7 @@ const fillRate = ref(50);
const errorMsg = ref(''); const errorMsg = ref('');
const difficultyCanvas = ref(null); const difficultyCanvas = ref(null);
const isDragging = ref(false); const isDragging = ref(false);
const cachedBackground = ref(null);
const drawMap = () => { const drawMap = () => {
const canvas = difficultyCanvas.value; const canvas = difficultyCanvas.value;
@@ -25,46 +26,42 @@ const drawMap = () => {
// Clear // Clear
ctx.clearRect(0, 0, width, height); ctx.clearRect(0, 0, width, height);
// Draw Gradient Background // Use cached background if available
// Optimization: Create an image data once if static, but here it's small enough. if (cachedBackground.value) {
const imgData = ctx.createImageData(width, height); ctx.putImageData(cachedBackground.value, 0, 0);
const data = imgData.data; } else {
// Draw Gradient Background (Heavy calculation)
const imgData = ctx.createImageData(width, height);
const data = imgData.data;
// Ranges: // Ranges:
// X: Fill Rate 10% -> 90% // X: Fill Rate 10% -> 90%
// Y: Size 5 -> 80 // Y: Size 5 -> 80
for (let y = 0; y < height; y++) { for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) { for (let x = 0; x < width; x++) {
// Map x, y to fillRate, size const normalizedX = x / width;
// y=0 -> size 80 (top), y=height -> size 5 (bottom) const normalizedY = 1 - (y / height); // 0 at bottom, 1 at top
// x=0 -> fill 10%, x=width -> fill 90%
const normalizedX = x / width; const fRate = 0.1 + normalizedX * 0.8; // 0.1 to 0.9
const normalizedY = 1 - (y / height); // 0 at bottom, 1 at top const sSize = 5 + normalizedY * 75; // 5 to 80
const fRate = 0.1 + normalizedX * 0.8; // 0.1 to 0.9 const { value } = calculateDifficulty(fRate, sSize);
const sSize = 5 + normalizedY * 75; // 5 to 80
const { value } = calculateDifficulty(fRate, sSize); // Color Mapping
const hue = 120 * (1 - value / 100);
const [r, g, b] = hslToRgb(hue / 360, 1, 0.5);
// Color Mapping: const index = (y * width + x) * 4;
// Green (0%) -> Yellow (50%) -> Red (100%) data[index] = r;
// Hue: 120 -> 0 data[index + 1] = g;
const hue = 120 * (1 - value / 100); data[index + 2] = b;
data[index + 3] = 255; // Alpha
// Convert HSL to RGB (Simplified) }
// Saturation 100%, Lightness 50% }
const [r, g, b] = hslToRgb(hue / 360, 1, 0.5); ctx.putImageData(imgData, 0, 0);
cachedBackground.value = imgData;
const index = (y * width + x) * 4;
data[index] = r;
data[index + 1] = g;
data[index + 2] = b;
data[index + 3] = 255; // Alpha
}
} }
ctx.putImageData(imgData, 0, 0);
// Draw current position // Draw current position
// Map current fillRate/size to x,y // Map current fillRate/size to x,y
@@ -166,6 +163,8 @@ const showAdvanced = ref(false);
const toggleAdvanced = () => { const toggleAdvanced = () => {
showAdvanced.value = !showAdvanced.value; showAdvanced.value = !showAdvanced.value;
if (showAdvanced.value) { if (showAdvanced.value) {
// Reset cache when opening to ensure size is correct if canvas resized
cachedBackground.value = null;
nextTick(drawMap); nextTick(drawMap);
} }
}; };