Created
May 21, 2025 12:15
-
-
Save kasparsj/e297e6ffff5a4d4aca3657912a17f993 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// General utility functions | |
function updateBrightness(value) { | |
document.getElementById('brightness-value').textContent = value; | |
fetch('/update_brightness?value=' + value) | |
.then(response => { | |
if (!response.ok) { | |
console.error('Failed to update brightness'); | |
} | |
}) | |
.catch(error => console.error('Error updating brightness:', error)); | |
} | |
function updateLayerBrightness(layer, value) { | |
document.getElementById('bg-brightness-value_' + layer).textContent = value; | |
fetch('/update_layer_brightness?layer=' + layer + '&value=' + value) | |
.then(response => { | |
if (!response.ok) { | |
console.error('Failed to update brightness'); | |
} | |
}) | |
.catch(error => console.error('Error updating brightness:', error)); | |
// Update the preview after changing brightness | |
setTimeout(() => updateLayerPreview(layer), 500); | |
} | |
function toggleLayerVisibility(layer, isVisible) { | |
fetch('/toggle_visible?layer=' + layer + '&visible=' + isVisible) | |
.then(response => { | |
if (!response.ok) { | |
console.error('Failed to toggle layer visibility'); | |
} else { | |
// Update the preview after toggling visibility | |
updateLayerPreview(layer); | |
} | |
}) | |
.catch(error => console.error('Error toggling visibility:', error)); | |
} | |
function updateLayerPreview(layer) { | |
const previewEl = document.getElementById('layer-preview-' + layer); | |
if (!previewEl) return; | |
// Show loading indicator | |
previewEl.style.background = 'linear-gradient(to right, #333, #555, #333)'; | |
// Fetch the colors for this layer | |
fetch('/get_colors?layer=' + layer + '&maxColors=300') | |
.then(response => response.json()) | |
.then(data => { | |
// Create the gradient preview | |
if (data.colors && data.colors.length > 0) { | |
// Create a flex container for the colors | |
const colorContainer = previewEl.querySelector('.color-container'); | |
// Clear existing preview | |
colorContainer.innerHTML = ''; | |
// Add color segments | |
data.colors.forEach(color => { | |
const segment = document.createElement('div'); | |
segment.style.flex = '1'; | |
segment.style.height = '100%'; | |
segment.style.backgroundColor = `rgb(${color.r}, ${color.g}, ${color.b})`; | |
colorContainer.appendChild(segment); | |
}); | |
previewEl.style.backgroundColor = 'transparent'; | |
} | |
}) | |
.catch(error => { | |
console.error('Error fetching layer preview:', error); | |
previewEl.style.backgroundColor = '#933'; // Error color | |
}); | |
} | |
// Palette management functions | |
function updateLedColor(layer, value, index = 0) { | |
const colorInput = document.querySelector(`.led_color[data-index='${index}']`); | |
if (colorInput) { | |
colorInput.value = value; | |
} | |
// Apply the color change immediately | |
applyColorGradient(layer); | |
} | |
function updateColorCount(layer) { | |
const container = document.querySelector(`#color-inputs-container-${layer}`); | |
const colorGroups = container.querySelectorAll('.color-input-group'); | |
const colorCount = colorGroups.length; | |
document.getElementById('color-count-' + layer).textContent = '(' + colorCount + ')'; | |
} | |
function getColorPositionData(layer) { | |
const container = document.querySelector(`#color-inputs-container-${layer}`); | |
const colorGroups = container.querySelectorAll('.color-input-group'); | |
let colorPairs = []; | |
// Build array of color-position pairs | |
colorGroups.forEach(group => { | |
const colorInput = group.querySelector('.led_color'); | |
const positionInput = group.querySelector('.led_position'); | |
if (colorInput) { | |
// Get position value and ensure it's in the correct range | |
let position = 0; | |
if (positionInput) { | |
position = parseFloat(positionInput.value); | |
position = Math.min(1, Math.max(0, position)); | |
} | |
colorPairs.push({ | |
color: colorInput.value, | |
position: position | |
}); | |
} | |
}); | |
// Sort by position | |
colorPairs.sort((a, b) => a.position - b.position); | |
// Separate into color and position arrays | |
const colorData = colorPairs.map(pair => pair.color); | |
const positionData = colorPairs.map(pair => pair.position); | |
return {colorData, positionData}; | |
} | |
function applyColorGradient(layer) { | |
const { colorData, positionData } = getColorPositionData(layer); | |
const formData = new FormData(); | |
formData.append('colors', JSON.stringify(colorData)); | |
formData.append('positions', JSON.stringify(positionData)); | |
formData.append('layer', layer); | |
updatePalette(formData); | |
} | |
function updatePalette(formData) { | |
// Get the layer ID from the form data | |
const layer = formData.get('layer'); | |
// Send using POST for larger data | |
fetch('/update_palette', { | |
method: 'POST', | |
body: formData | |
}) | |
.then(response => { | |
if (!response.ok) { | |
console.error('Failed to update colors'); | |
} else { | |
// Update the layer preview after palette changes | |
setTimeout(() => updateLayerPreview(layer), 300); | |
} | |
}); | |
} | |
function savePalette(layer) { | |
// Get current palette data | |
const colorGroups = document.querySelectorAll('.color-input-group'); | |
let colorPairs = []; | |
colorGroups.forEach(group => { | |
const colorInput = group.querySelector('.led_color'); | |
const positionInput = group.querySelector('.led_position'); | |
if (colorInput) { | |
let position = 0; | |
if (positionInput) { | |
position = parseFloat(positionInput.value); | |
position = Math.min(1, Math.max(0, position)); | |
} | |
colorPairs.push({ | |
color: colorInput.value, | |
position: position | |
}); | |
} | |
}); | |
// Check if we have any colors to save | |
if (colorPairs.length === 0) { | |
alert('Please add at least one color to the palette before saving.'); | |
return; | |
} | |
// Sort by position | |
colorPairs.sort((a, b) => a.position - b.position); | |
// Prompt for palette name | |
const paletteName = prompt('Enter a name for this palette:', ''); | |
if (!paletteName || paletteName.trim() === '') { | |
// User cancelled or entered empty name | |
return; | |
} | |
// Prepare the data | |
const paletteData = { | |
name: paletteName.trim(), | |
colors: colorPairs.map(pair => pair.color), | |
positions: colorPairs.map(pair => pair.position), | |
colorRule: document.getElementById('color_rule_' + layer).value, | |
interMode: document.getElementById('inter_mode_' + layer).value, | |
wrapMode: document.getElementById('wrap_mode_' + layer).value, | |
segmentation: document.getElementById('segmentation_' + layer).value | |
}; | |
// Send to server | |
fetch('/save_palette', { | |
method: 'POST', | |
headers: { | |
'Content-Type': 'application/json' | |
}, | |
body: JSON.stringify(paletteData) | |
}) | |
.then(response => { | |
if (response.ok) { | |
return response.json(); | |
} | |
throw new Error('Failed to save palette'); | |
}) | |
.then(data => { | |
alert(`Palette '${paletteName}' saved successfully!`); | |
// Add a delay before reloading to give SPIFFS time to complete the write | |
setTimeout(() => { | |
// Reload the predefined palette dropdown to include the new palette | |
location.reload(); | |
}, 1000); // 1 second delay | |
}) | |
.catch(error => { | |
alert('Error saving palette: ' + error.message); | |
}); | |
} | |
function selectPredefinedPalette(layer, value) { | |
if (value === '-1') { | |
// Custom colors, do nothing | |
return; | |
} | |
// Fetch palette colors from server | |
fetch('/get_palette_colors?index=' + value + '&layer=' + layer) | |
.then(response => response.json()) | |
.then(data => { | |
// Clear existing colors | |
const container = document.getElementById('color-inputs-container-' + layer); | |
container.innerHTML = ''; | |
// Add colors from the palette | |
data.colors.forEach((color, index) => { | |
// Create a new color input group | |
const newGroup = document.createElement('div'); | |
newGroup.className = 'color-input-group'; | |
newGroup.style = 'display: flex; align-items: center; margin-bottom: 10px;'; | |
// Create color input | |
const colorInput = document.createElement('input'); | |
colorInput.type = 'color'; | |
colorInput.className = 'led_color'; | |
colorInput.setAttribute('data-index', index); | |
colorInput.value = color; | |
colorInput.style = 'flex: 0.7; height: 40px;'; | |
// Create position input | |
const positionInput = document.createElement('input'); | |
positionInput.type = 'number'; | |
positionInput.className = 'led_position'; | |
positionInput.setAttribute('data-index', index); | |
positionInput.min = 0; | |
positionInput.max = 1; | |
positionInput.step = 0.01; | |
positionInput.value = data.positions[index]; | |
positionInput.style = 'flex: 0.3; margin-left: 10px;'; | |
// Create remove button | |
const removeButton = document.createElement('a'); | |
removeButton.href = '#'; | |
removeButton.className = 'remove-color'; | |
removeButton.style = 'margin-left: 10px; color: white; background: #cc3300; padding: 5px 10px; text-decoration: none; border-radius: 3px;'; | |
removeButton.innerHTML = '×'; | |
removeButton.addEventListener('click', function(e) { | |
e.preventDefault(); | |
removeColorInput(newGroup); | |
}); | |
// Add elements to group | |
newGroup.appendChild(colorInput); | |
newGroup.appendChild(positionInput); | |
newGroup.appendChild(removeButton); | |
// Add group to container | |
container.appendChild(newGroup); | |
// Add color input event listener | |
colorInput.addEventListener('input', function() { | |
updateLedColor(layer, this.value, index); | |
}); | |
// Add position input event listener | |
positionInput.addEventListener('change', function() { | |
applyColorGradient(layer); | |
}); | |
}); | |
// Update color rule, interpolation mode, and wrap mode if provided | |
if (data.colorRule !== undefined) { | |
const colorRuleSelect = document.getElementById('color_rule_' + layer); | |
if (colorRuleSelect) { | |
colorRuleSelect.value = data.colorRule; | |
} | |
} | |
if (data.interMode !== undefined) { | |
const interModeSelect = document.getElementById('inter_mode_' + layer); | |
if (interModeSelect) { | |
interModeSelect.value = data.interMode; | |
} | |
} | |
if (data.wrapMode !== undefined) { | |
const wrapModeSelect = document.getElementById('wrap_mode_' + layer); | |
if (wrapModeSelect) { | |
wrapModeSelect.value = data.wrapMode; | |
} | |
} | |
// Interpolation multiplier was removed | |
if (data.segmentation !== undefined) { | |
const segmentationInput = document.getElementById('segmentation_' + layer); | |
if (segmentationInput) { | |
segmentationInput.value = Number(data.segmentation).toFixed(1); | |
} | |
} | |
// Create form data and apply the new colors | |
const { colorData, positionData } = getColorPositionData(layer); | |
const formData = new FormData(); | |
formData.append('colors', JSON.stringify(colorData)); | |
formData.append('positions', JSON.stringify(positionData)); | |
formData.append('layer', layer); | |
// Also include other palette properties if they were updated | |
if (data.colorRule !== undefined) { | |
formData.append('colorRule', data.colorRule); | |
} | |
if (data.interMode !== undefined) { | |
formData.append('interMode', data.interMode); | |
} | |
if (data.wrapMode !== undefined) { | |
formData.append('wrapMode', data.wrapMode); | |
} | |
if (data.segmentation !== undefined) { | |
formData.append('segmentation', data.segmentation); | |
} | |
// Send update to server | |
updatePalette(formData); | |
// Update color count | |
updateColorCount(layer); | |
}) | |
.catch(error => console.error('Error loading palette:', error)); | |
} | |
function addColorInput(layer) { | |
const container = document.querySelector(`#color-inputs-container-${layer}`); | |
const colorInputGroups = container.querySelectorAll('.color-input-group'); | |
const newIndex = colorInputGroups.length; | |
// Create new color input group | |
const newGroup = document.createElement('div'); | |
newGroup.className = 'color-input-group'; | |
newGroup.style = 'display: flex; align-items: center; margin-bottom: 10px;'; | |
// Create color input - always start with black (unset) color | |
const colorInput = document.createElement('input'); | |
colorInput.type = 'color'; | |
colorInput.className = 'led_color'; | |
colorInput.setAttribute('data-index', newIndex); | |
colorInput.value = '#000000'; // Start with black (unset) | |
colorInput.style = 'height: 40px;'; | |
// Create position input - default position based on index | |
const positionInput = document.createElement('input'); | |
positionInput.type = 'number'; | |
positionInput.className = 'led_position'; | |
positionInput.setAttribute('data-index', newIndex); | |
positionInput.min = 0; | |
positionInput.max = 1; | |
positionInput.step = 0.01; | |
// If colors already exist, position at the end | |
positionInput.value = colorInputGroups.length > 0 ? 1.0 : 0.0; | |
positionInput.style = 'flex: 1; margin-left: 10px;'; | |
// Create remove button | |
const removeButton = document.createElement('a'); | |
removeButton.href = '#'; | |
removeButton.className = 'remove-color'; | |
removeButton.style = 'margin-left: 10px; color: white; background: #cc3300; padding: 5px 10px; text-decoration: none; border-radius: 3px;'; | |
removeButton.innerHTML = '×'; | |
removeButton.addEventListener('click', function(e) { | |
e.preventDefault(); | |
removeColorInput(newGroup); | |
}); | |
// Add elements to group | |
newGroup.appendChild(colorInput); | |
newGroup.appendChild(positionInput); | |
newGroup.appendChild(removeButton); | |
// Add group to container | |
container.appendChild(newGroup); | |
// Add color input event listener | |
colorInput.addEventListener('input', function() { | |
const colorInput = document.querySelector(`.led_color[data-index='${newIndex}']`); | |
if (colorInput) { | |
colorInput.value = this.value; | |
} | |
applyColorGradient(layer); | |
}); | |
// Add position input event listener | |
positionInput.addEventListener('change', function() { | |
applyColorGradient(layer); | |
}); | |
applyColorGradient(layer); | |
} | |
function removeColorInput(group) { | |
const container = group.closest('.color-inputs-container'); | |
const allGroups = container.querySelectorAll('.color-input-group'); | |
// Check if we already have only 1 input - if so, don't remove | |
if (allGroups.length <= 1) { | |
// Don't allow removing the last color | |
return; | |
} | |
group.remove(); | |
// Re-index the remaining color inputs | |
const inputs = document.querySelectorAll('.led_color'); | |
inputs.forEach((input, index) => { | |
input.setAttribute('data-index', index); | |
}); | |
// Apply the changes immediately | |
applyColorGradient(layer); | |
// Update the color count | |
updateColorCount(layer); | |
} | |
function addLayer() { | |
fetch('/add_layer', { | |
method: 'POST' | |
}) | |
.then(response => { | |
if (response.ok) { | |
// Reload the page to show the new layer | |
location.reload(); | |
} else { | |
console.error('Failed to add layer'); | |
alert('Failed to add layer'); | |
} | |
}) | |
.catch(error => { | |
console.error('Error adding layer:', error); | |
alert('Error adding layer: ' + error.message); | |
}); | |
} | |
function removeLayer(layer) { | |
if (confirm('Are you sure you want to remove Layer ' + (layer + 1) + '?')) { | |
fetch('/remove_layer?layer=' + layer, { | |
method: 'POST' | |
}) | |
.then(response => { | |
if (response.ok) { | |
// Reload the page to show the updated layers | |
location.reload(); | |
} else { | |
console.error('Failed to remove layer'); | |
alert('Failed to remove layer'); | |
} | |
}) | |
.catch(error => { | |
console.error('Error removing layer:', error); | |
alert('Error removing layer: ' + error.message); | |
}); | |
} | |
} | |
// Visual page functions | |
function getRGBColor(colorObj) { | |
return `rgb(${colorObj.r}, ${colorObj.g}, ${colorObj.b})`; | |
} | |
function createLayerControls() { | |
const container = document.createElement('div'); | |
container.style.display = 'flex'; | |
container.style.marginTop = '10px'; | |
container.style.gap = '10px'; | |
// Layer selector | |
const layerSelect = document.createElement('select'); | |
layerSelect.id = 'layer-select'; | |
layerSelect.style.padding = '5px'; | |
layerSelect.style.flexGrow = '1'; | |
// Add 'All layers' option | |
const allOption = document.createElement('option'); | |
allOption.value = '-1'; | |
allOption.textContent = 'All layers'; | |
allOption.selected = true; | |
layerSelect.appendChild(allOption); | |
// Add options for each layer (max 8 layers) | |
for (let i = 0; i < 8; i++) { | |
const option = document.createElement('option'); | |
option.value = i; | |
option.textContent = `Layer ${i+1}`; | |
layerSelect.appendChild(option); | |
} | |
container.appendChild(layerSelect); | |
return container; | |
} | |
function fetchLEDColors(maxColors = 0, layer = -1) { | |
document.getElementById('led-strip').innerHTML = '<div class="loading-indicator" style="margin: auto; color: #888;">Loading LED colors...</div>'; | |
document.getElementById('led-info').innerHTML = 'Hover over LEDs to see their RGBW values.'; | |
let url = '/get_colors'; | |
let params = []; | |
if (maxColors > 0) { params.push('maxColors=' + maxColors); } | |
if (layer >= 0) { params.push('layer=' + layer); } | |
if (params.length > 0) { url += '?' + params.join('&'); } | |
fetch(url) | |
.then(response => response.json()) | |
.then(data => { | |
const stripContainer = document.getElementById('led-strip'); | |
stripContainer.innerHTML = ''; | |
data.colors.forEach((colorObj, index) => { | |
const led = document.createElement('div'); | |
led.style.backgroundColor = getRGBColor(colorObj); | |
led.style.height = '100%'; | |
led.style.flexGrow = '1'; | |
led.style.minWidth = '10px'; | |
led.style.margin = '0 1px'; | |
led.style.borderRadius = '2px'; | |
if (colorObj.w > 100) { | |
led.style.border = '2px solid white'; | |
led.style.boxSizing = 'border-box'; | |
} | |
led.title = `LED ${index}: R:${colorObj.r} G:${colorObj.g} B:${colorObj.b} W:${colorObj.w}`; | |
stripContainer.appendChild(led); | |
}); | |
document.getElementById('led-info').innerHTML = | |
'Hover over LEDs to see their RGBW values. <br>' + wattageInfo; | |
}) | |
.catch(error => { | |
console.error('Error fetching LED colors:', error); | |
document.getElementById('led-strip').innerHTML = '<div style="margin: auto; color: #f88;">Error loading LED colors</div>'; | |
}); | |
} | |
// Palette management functions from WebServerPalettes.h | |
function deletePalette() { | |
const paletteSelect = document.getElementById('user_palette'); | |
if (!paletteSelect || !paletteSelect.value.startsWith('u')) { | |
alert('Please select a user palette to delete'); | |
return; | |
} | |
const userPaletteIndex = paletteSelect.value.substring(1); | |
const selectedOption = paletteSelect.options[paletteSelect.selectedIndex]; | |
const paletteName = selectedOption.text.replace('User: ', ''); | |
// Confirm deletion | |
if (!confirm(`Are you sure you want to delete the palette "${paletteName}"?`)) { | |
return; | |
} | |
// Send delete request to server | |
fetch('/delete_palette?index=' + userPaletteIndex) | |
.then(response => { | |
if (response.ok) { | |
return response.json(); | |
} | |
throw new Error('Failed to delete palette'); | |
}) | |
.then(data => { | |
alert(`Palette '${paletteName}' deleted successfully!`); | |
// Add a delay before reloading to ensure the palette file is updated | |
setTimeout(() => { | |
// Reload the page to update the palette dropdown | |
location.reload(); | |
}, 1000); // 1 second delay | |
}) | |
.catch(error => { | |
alert('Error deleting palette: ' + error.message); | |
}); | |
} | |
function toggleDeleteButton(selectValue) { | |
const deleteButton = document.getElementById('delete-palette-btn'); | |
if (deleteButton) { | |
// Show delete button only for user palettes (value starts with 'u') | |
if (selectValue && selectValue.startsWith('u')) { | |
deleteButton.style.display = 'block'; | |
} else { | |
deleteButton.style.display = 'none'; | |
} | |
} | |
} | |
function selectUserPalette(value) { | |
// Toggle delete button visibility | |
toggleDeleteButton(value); | |
// Show/hide palette details based on selection | |
const paletteDetails = document.getElementById('palette_details'); | |
if (paletteDetails) { | |
paletteDetails.style.display = (value === '-1') ? 'none' : 'block'; | |
} | |
if (value === '-1') { | |
// No palette selected, just hide details | |
return; | |
} | |
// Fetch palette colors from server | |
fetch('/get_palette_colors?index=' + value) | |
.then(response => response.json()) | |
.then(data => { | |
// Clear existing colors | |
const container = document.getElementById('color-inputs-container'); | |
container.innerHTML = ''; | |
// Add colors from the palette | |
data.colors.forEach((color, index) => { | |
// Create a new color input group | |
const newGroup = document.createElement('div'); | |
newGroup.className = 'color-input-group'; | |
newGroup.style = 'display: flex; align-items: center; margin-bottom: 10px;'; | |
// Create color input | |
const colorInput = document.createElement('input'); | |
colorInput.type = 'color'; | |
colorInput.className = 'led_color'; | |
colorInput.setAttribute('data-index', index); | |
colorInput.value = color; | |
colorInput.style = 'flex: 0.7; height: 40px;'; | |
// Create position input | |
const positionInput = document.createElement('input'); | |
positionInput.type = 'number'; | |
positionInput.className = 'led_position'; | |
positionInput.setAttribute('data-index', index); | |
positionInput.min = 0; | |
positionInput.max = 1; | |
positionInput.step = 0.01; | |
positionInput.value = data.positions[index]; | |
positionInput.style = 'flex: 0.3; margin-left: 10px;'; | |
// Add elements to group | |
newGroup.appendChild(colorInput); | |
newGroup.appendChild(positionInput); | |
// Add group to container | |
container.appendChild(newGroup); | |
}); | |
// Update color rule, interpolation mode, and wrap mode if provided | |
if (data.colorRule !== undefined) { | |
const colorRuleSelect = document.getElementById('color_rule'); | |
if (colorRuleSelect) { | |
colorRuleSelect.value = data.colorRule; | |
} | |
} | |
if (data.interMode !== undefined) { | |
const interModeSelect = document.getElementById('inter_mode'); | |
if (interModeSelect) { | |
interModeSelect.value = data.interMode; | |
} | |
} | |
if (data.wrapMode !== undefined) { | |
const wrapModeSelect = document.getElementById('wrap_mode'); | |
if (wrapModeSelect) { | |
wrapModeSelect.value = data.wrapMode; | |
} | |
} | |
// Interpolation multiplier was removed | |
if (data.segmentation !== undefined) { | |
const segmentationInput = document.getElementById('segmentation'); | |
if (segmentationInput) { | |
segmentationInput.value = Number(data.segmentation).toFixed(1); | |
} | |
} | |
// Update color count | |
updateColorCount(); | |
}) | |
.catch(error => console.error('Error loading palette:', error)); | |
} | |
// Emitter control functions from WebServerEmitter.h | |
function updateemitterMinSpeed(value) { | |
document.getElementById('min-speed-value').textContent = value; | |
fetch('/update_emitter_min_speed?value=' + value) | |
.then(response => { | |
if (!response.ok) { | |
console.error('Failed to update min speed'); | |
} | |
}) | |
.catch(error => console.error('Error updating min speed:', error)); | |
} | |
function updateMaxSpeed(value) { | |
document.getElementById('max-speed-value').textContent = value; | |
fetch('/update_emitter_max_speed?value=' + value) | |
.then(response => { | |
if (!response.ok) { | |
console.error('Failed to update max speed'); | |
} | |
}) | |
.catch(error => console.error('Error updating max speed:', error)); | |
} | |
function updateMinDuration(value) { | |
document.getElementById('min-duration-value').textContent = value; | |
fetch('/update_emitter_min_dur?value=' + value); | |
} | |
function updateMaxDuration(value) { | |
document.getElementById('max-duration-value').textContent = value; | |
fetch('/update_emitter_max_dur?value=' + value); | |
} | |
function updateEmitterMinSat(value) { | |
document.getElementById('emitter-min-sat-value').textContent = value; | |
fetch('/update_emitter_min_sat?value=' + value); | |
} | |
function updateEmitterMaxSat(value) { | |
document.getElementById('emitter-max-sat-value').textContent = value; | |
fetch('/update_emitter_max_sat?value=' + value); | |
} | |
function updateEmitterMinVal(value) { | |
document.getElementById('emitter-min-val-value').textContent = value; | |
fetch('/update_emitter_min_val?value=' + value); | |
} | |
function updateEmitterMaxVal(value) { | |
document.getElementById('emitter-max-val-value').textContent = value; | |
fetch('/update_emitter_max_val?value=' + value); | |
} | |
function updateMinNext(value) { | |
document.getElementById('min-next-value').textContent = value; | |
fetch('/update_emitter_min_next?value=' + value); | |
} | |
function updateMaxNext(value) { | |
document.getElementById('max-next-value').textContent = value; | |
fetch('/update_emitter_max_next?value=' + value); | |
} | |
function updateEmitterFrom(value) { | |
document.getElementById('emitter-from-value').textContent = value; | |
fetch('/update_emitter_from?value=' + value); | |
} | |
// Initialize event listeners when document is loaded | |
document.addEventListener('DOMContentLoaded', function() { | |
// Settings page brightness slider | |
const brightnessSlider = document.getElementById('max_brightness'); | |
if (brightnessSlider) { | |
brightnessSlider.addEventListener('input', function() { | |
document.getElementById('brightness-value').textContent = this.value; | |
}); | |
brightnessSlider.addEventListener('change', function() { | |
updateBrightness(this.value); | |
}); | |
} | |
// Initialize layer color previews | |
document.querySelectorAll('.layer-preview').forEach(preview => { | |
const layerId = parseInt(preview.id.split('-').pop()); | |
updateLayerPreview(layerId); | |
// Add click event to toggle layer fields visibility | |
preview.addEventListener('click', function() { | |
const layerId = this.getAttribute('data-layer'); | |
const fieldsContainer = document.getElementById(`layer-fields-${layerId}`); | |
if (fieldsContainer) { | |
const isHidden = fieldsContainer.style.display === 'none'; | |
fieldsContainer.style.display = isHidden ? 'block' : 'none'; | |
// Update visual indicator of expanded state | |
this.style.border = isHidden ? '1px solid white' : 'none'; | |
// Update the arrow indicator | |
const arrow = this.querySelector('.arrow'); | |
if (arrow) { | |
arrow.innerHTML = isHidden ? '▼' : '▶'; | |
} | |
} | |
}); | |
}); | |
// Add Layer button event listener | |
const addLayerBtn = document.getElementById('add-layer-btn'); | |
if (addLayerBtn) { | |
addLayerBtn.addEventListener('click', addLayer); | |
} | |
// Remove Layer button event listeners | |
const removeLayerBtns = document.querySelectorAll('.remove-layer-btn'); | |
removeLayerBtns.forEach(btn => { | |
btn.addEventListener('click', function() { | |
const layer = parseInt(this.getAttribute('data-layer')); | |
removeLayer(layer); | |
}); | |
}); | |
// Initialize the remove buttons for all color groups | |
const allRemoveButtons = document.querySelectorAll('.remove-color'); | |
allRemoveButtons.forEach(button => { | |
button.addEventListener('click', function(e) { | |
e.preventDefault(); | |
const group = this.closest('.color-input-group'); | |
const container = group.closest('.color-inputs-container'); | |
const layerId = parseInt(container.id.split('-').pop()); | |
if (group) { | |
removeColorInput(group, layerId); | |
} | |
}); | |
}); | |
// Initialize the color count for all layers | |
document.querySelectorAll('.color-inputs-container').forEach(container => { | |
const layerId = container.getAttribute('data-layer'); | |
updateColorCount(layerId); | |
}); | |
// Add event listeners for Add Color buttons | |
document.querySelectorAll('.add-color-btn').forEach(btn => { | |
btn.addEventListener('click', function() { | |
const layerId = this.getAttribute('data-layer'); | |
addColorInput(layerId); | |
}); | |
}); | |
// Color input handling - initialize all color inputs | |
document.querySelectorAll('.led_color').forEach(input => { | |
input.addEventListener('input', function() { | |
const container = this.closest('.color-inputs-container'); | |
const layerId = container.getAttribute('data-layer'); | |
const index = parseInt(this.getAttribute('data-index')); | |
updateLedColor(layerId, this.value, index); | |
}); | |
}); | |
// Position input handling - initialize all position inputs | |
document.querySelectorAll('.led_position').forEach(input => { | |
input.addEventListener('change', function() { | |
const container = this.closest('.color-inputs-container'); | |
const layerId = container.getAttribute('data-layer'); | |
applyColorGradient(layerId); | |
}); | |
}); | |
// Color rule selects | |
document.querySelectorAll('.color-rule').forEach(select => { | |
select.addEventListener('change', function() { | |
const formData = new FormData(); | |
formData.append('layer', this.getAttribute('data-layer')); | |
formData.append('colorRule', this.value); | |
updatePalette(formData); | |
}); | |
}); | |
// Interpolation mode selects | |
document.querySelectorAll('.inter-mode').forEach(select => { | |
select.addEventListener('change', function() { | |
const formData = new FormData(); | |
formData.append('layer', this.getAttribute('data-layer')); | |
formData.append('interMode', this.value); | |
updatePalette(formData); | |
}); | |
}); | |
// Wrap mode selects | |
document.querySelectorAll('.wrap-mode').forEach(select => { | |
select.addEventListener('change', function() { | |
const formData = new FormData(); | |
formData.append('layer', this.getAttribute('data-layer')); | |
formData.append('wrapMode', this.value); | |
updatePalette(formData); | |
}); | |
}); | |
// Blend mode selects | |
document.querySelectorAll('.blend-mode').forEach(select => { | |
select.addEventListener('change', function() { | |
const layerId = this.getAttribute('data-layer'); | |
fetch('/update_blend_mode?layer=' + layerId + '&mode=' + this.value) | |
.then(response => { | |
if (!response.ok) { | |
console.error('Failed to update blend mode'); | |
} else { | |
// Update the layer preview after blend mode changes | |
setTimeout(() => updateLayerPreview(layerId), 300); | |
} | |
}); | |
}); | |
}); | |
// Segmentation inputs | |
document.querySelectorAll('.segmentation').forEach(input => { | |
input.addEventListener('change', function() { | |
const formData = new FormData(); | |
formData.append('layer', this.getAttribute('data-layer')); | |
formData.append('segmentation', this.value); | |
updatePalette(formData); | |
}); | |
}); | |
// Predefined palette selects | |
document.querySelectorAll('[id^="predefined_palette_"]').forEach(select => { | |
select.addEventListener('change', function() { | |
const layerId = this.getAttribute('data-layer'); | |
selectPredefinedPalette(layerId, this.value); | |
}); | |
}); | |
// Save palette buttons | |
document.querySelectorAll('.save-palette-btn').forEach(btn => { | |
btn.addEventListener('click', function() { | |
const layerId = this.getAttribute('data-layer'); | |
savePalette(layerId); | |
}); | |
}); | |
// Layer visibility checkboxes | |
document.querySelectorAll('.layer-visibility').forEach(checkbox => { | |
checkbox.addEventListener('change', function() { | |
const layerId = this.getAttribute('data-layer'); | |
toggleLayerVisibility(layerId, this.checked); | |
}); | |
}); | |
// Layer brightness sliders | |
document.querySelectorAll('.layer-brightness').forEach(slider => { | |
slider.addEventListener('input', function() { | |
const layerId = this.getAttribute('data-layer'); | |
document.getElementById('bg-brightness-value_' + layerId).textContent = this.value; | |
}); | |
slider.addEventListener('change', function() { | |
const layerId = this.getAttribute('data-layer'); | |
updateLayerBrightness(layerId, this.value); | |
}); | |
}); | |
// Visual page initialization | |
const controlsContainer = document.getElementById('visualization-controls'); | |
if (controlsContainer) { | |
controlsContainer.appendChild(createLayerControls()); | |
// Initialize colors on page load | |
fetchLEDColors(); | |
// Add refresh button click handler | |
document.getElementById('refresh-leds').addEventListener('click', function() { | |
const layerValue = parseInt(document.getElementById('layer-select').value); | |
fetchLEDColors(0, layerValue); | |
}); | |
// Add layer selector change handler | |
document.getElementById('layer-select').addEventListener('change', function() { | |
const layerValue = parseInt(this.value); | |
fetchLEDColors(0, layerValue); | |
}); | |
} | |
// Palettes page initialization | |
const userPaletteSelect = document.getElementById('user_palette'); | |
if (userPaletteSelect) { | |
userPaletteSelect.addEventListener('change', function() { | |
selectUserPalette(this.value); | |
}); | |
// Initialize Delete Palette button | |
const deletePaletteBtn = document.getElementById('delete-palette-btn'); | |
if (deletePaletteBtn) { | |
deletePaletteBtn.addEventListener('click', function() { | |
deletePalette(); | |
}); | |
} | |
// Set initial state of delete button based on selection | |
toggleDeleteButton(userPaletteSelect.value); | |
} | |
// Emitter page initialization | |
const emitterMinSpeedSlider = document.getElementById('emitter_min_speed'); | |
if (emitterMinSpeedSlider) { | |
emitterMinSpeedSlider.addEventListener('change', function() { | |
updateemitterMinSpeed(this.value); | |
}); | |
const emitterMaxSpeedSlider = document.getElementById('emitter_max_speed'); | |
emitterMaxSpeedSlider.addEventListener('change', function() { | |
updateMaxSpeed(this.value); | |
}); | |
const emitterMinDurSlider = document.getElementById('emitter_min_dur'); | |
emitterMinDurSlider.addEventListener('change', function() { | |
updateMinDuration(this.value); | |
}); | |
const emitterMaxDurSlider = document.getElementById('emitter_max_dur'); | |
emitterMaxDurSlider.addEventListener('change', function() { | |
updateMaxDuration(this.value); | |
}); | |
// Add listeners for other emitter controls as well | |
const emitterMinSatSlider = document.getElementById('emitter_min_sat'); | |
if (emitterMinSatSlider) { | |
emitterMinSatSlider.addEventListener('change', function() { | |
updateEmitterMinSat(this.value); | |
}); | |
} | |
const emitterMaxSatSlider = document.getElementById('emitter_max_sat'); | |
if (emitterMaxSatSlider) { | |
emitterMaxSatSlider.addEventListener('change', function() { | |
updateEmitterMaxSat(this.value); | |
}); | |
} | |
const emitterMinValSlider = document.getElementById('emitter_min_val'); | |
if (emitterMinValSlider) { | |
emitterMinValSlider.addEventListener('change', function() { | |
updateEmitterMinVal(this.value); | |
}); | |
} | |
const emitterMaxValSlider = document.getElementById('emitter_max_val'); | |
if (emitterMaxValSlider) { | |
emitterMaxValSlider.addEventListener('change', function() { | |
updateEmitterMaxVal(this.value); | |
}); | |
} | |
const emitterMinNextSlider = document.getElementById('emitter_min_next'); | |
if (emitterMinNextSlider) { | |
emitterMinNextSlider.addEventListener('change', function() { | |
updateMinNext(this.value); | |
}); | |
} | |
const emitterMaxNextSlider = document.getElementById('emitter_max_next'); | |
if (emitterMaxNextSlider) { | |
emitterMaxNextSlider.addEventListener('change', function() { | |
updateMaxNext(this.value); | |
}); | |
} | |
const emitterFromInput = document.getElementById('emitter_from'); | |
if (emitterFromInput) { | |
emitterFromInput.addEventListener('change', function() { | |
updateEmitterFrom(this.value); | |
}); | |
} | |
} | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment