2023-04-08 20:02:49 +02:00
|
|
|
|
|
|
|
<!DOCTYPE html>
|
|
|
|
<html>
|
|
|
|
<head>
|
|
|
|
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
|
|
|
|
<meta http-equiv="Pragma" content="no-cache">
|
|
|
|
<meta http-equiv="Expires" content="0">
|
2023-04-14 18:33:03 +02:00
|
|
|
<title>WLED Custom Palette Editor</title>
|
2023-04-08 20:02:49 +02:00
|
|
|
<script type="text/javascript">
|
|
|
|
var d = document;
|
|
|
|
function gId(e) {return d.getElementById(e);}
|
|
|
|
function cE(e) {return d.createElement(e);}
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<style>
|
|
|
|
body {
|
|
|
|
font-family: Arial, sans-serif;
|
|
|
|
background-color: #111;
|
|
|
|
font-size: 16px;
|
|
|
|
color: #ddd;
|
|
|
|
margin: 0 10px;
|
|
|
|
font-family: Arial, sans-serif;
|
|
|
|
line-height: 0.5;
|
|
|
|
}
|
|
|
|
#parent-container {
|
|
|
|
position: relative;
|
|
|
|
width: 100%;
|
|
|
|
height: 20px;
|
2023-04-12 09:15:38 +02:00
|
|
|
|
2023-04-08 20:02:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#bottomContainer {
|
|
|
|
position: absolute;
|
|
|
|
margin-top: 50px;
|
2023-04-12 09:15:38 +02:00
|
|
|
|
2023-04-08 20:02:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#gradient-box {
|
|
|
|
width: 100%;
|
|
|
|
height: 100%;
|
|
|
|
}
|
|
|
|
|
|
|
|
.color-marker {
|
|
|
|
position: absolute;
|
|
|
|
height: 30px;
|
|
|
|
width: 7px;
|
|
|
|
border-radius: 3px;
|
|
|
|
background-color: rgb(192, 192, 192);
|
|
|
|
border: 2px solid rgba(68, 68, 68, 0.5);
|
|
|
|
top: 50%;
|
|
|
|
transform: translateY(-50%);
|
|
|
|
z-index: 2;
|
|
|
|
}
|
|
|
|
.color-picker-marker {
|
|
|
|
position: absolute;
|
|
|
|
height: 7px;
|
|
|
|
width: 7px;
|
|
|
|
border-radius: 3px;
|
|
|
|
background-color: rgb(192, 192, 192);
|
|
|
|
border: 2px solid rgba(68, 68, 68, 0.5);
|
|
|
|
top: 150%;
|
|
|
|
z-index: 2;
|
|
|
|
}
|
|
|
|
.delete-marker {
|
|
|
|
position: absolute;
|
|
|
|
height: 5px;
|
|
|
|
width: 5px;
|
|
|
|
border-radius: 3px;
|
|
|
|
background-color: rgb(255, 255, 255);
|
|
|
|
border: 3px solid rgb(155, 40, 40);
|
|
|
|
top: 220%;
|
|
|
|
z-index: 2;
|
|
|
|
}
|
|
|
|
.color-picker{
|
|
|
|
position: absolute;
|
|
|
|
height: 1px;
|
|
|
|
width: 1px;
|
|
|
|
border: 1px;
|
|
|
|
top: 150%;
|
|
|
|
z-index: 1;
|
|
|
|
border-color: #111;
|
|
|
|
background-color: #111;
|
|
|
|
}
|
|
|
|
.buttonclass {
|
|
|
|
padding: 0,0,0,0px;
|
|
|
|
margin: 0,0,0,0px;
|
|
|
|
vertical-align: bottom;
|
|
|
|
background-color: #111;
|
|
|
|
}
|
|
|
|
#bottomContainer span {
|
|
|
|
display: inline-flex;
|
|
|
|
align-items: center;
|
|
|
|
color: #fff;
|
|
|
|
font-family: Arial, sans-serif;
|
|
|
|
font-size: 12px;
|
|
|
|
vertical-align: middle;
|
|
|
|
}
|
|
|
|
#info {
|
2023-04-12 09:15:38 +02:00
|
|
|
display: "";
|
2023-04-08 20:02:49 +02:00
|
|
|
text-align: center;
|
|
|
|
color: #fff;
|
|
|
|
font-family: Arial, sans-serif;
|
|
|
|
font-size: 12px;
|
|
|
|
position: relative;
|
2023-04-23 21:32:52 +02:00
|
|
|
margin-top: 10px;
|
2023-04-09 14:18:22 +02:00
|
|
|
line-height: 1;
|
2023-04-12 09:15:38 +02:00
|
|
|
|
2023-04-08 20:02:49 +02:00
|
|
|
}
|
2023-04-23 21:32:52 +02:00
|
|
|
.wrap{
|
|
|
|
width: 800px;
|
|
|
|
margin: 0 auto;
|
|
|
|
}
|
|
|
|
.palette{
|
|
|
|
height: 20px;
|
|
|
|
}
|
|
|
|
.paletteGradients{
|
|
|
|
flex: 1;
|
|
|
|
height: 20px;
|
|
|
|
border-radius: 3px;
|
|
|
|
}
|
|
|
|
.palettesMain {
|
|
|
|
margin-top: 50px;
|
|
|
|
width: 100%;
|
|
|
|
}
|
|
|
|
#palTop{
|
|
|
|
height: fit-content;
|
|
|
|
text-align: center;
|
|
|
|
color: #fff;
|
|
|
|
font-family: Arial, sans-serif;
|
|
|
|
font-size: 12px;
|
|
|
|
position: relative;
|
|
|
|
line-height: 1;
|
|
|
|
}
|
|
|
|
.palGradientParent{
|
|
|
|
display: flex;
|
|
|
|
align-items: center;
|
|
|
|
height: fit-content;
|
|
|
|
margin-top: 10px;
|
|
|
|
text-align: center;
|
|
|
|
color: #fff;
|
|
|
|
font-family: Arial, sans-serif;
|
|
|
|
font-size: 12px;
|
|
|
|
position: relative;
|
|
|
|
line-height: 1;
|
|
|
|
}
|
|
|
|
.buttonsDiv{
|
|
|
|
display: inline-flex;
|
|
|
|
margin-left: 5px;
|
|
|
|
width: 50px;
|
|
|
|
}
|
|
|
|
.sendSpan{
|
|
|
|
cursor: pointer;
|
|
|
|
}
|
|
|
|
.editSpan{
|
|
|
|
cursor: pointer;
|
|
|
|
}
|
2023-04-08 20:02:49 +02:00
|
|
|
</style>
|
|
|
|
</head>
|
|
|
|
<body>
|
2023-04-23 21:32:52 +02:00
|
|
|
<div id="wrap" class="wrap">
|
2023-04-08 20:02:49 +02:00
|
|
|
<div style="display: flex; justify-content: center;">
|
|
|
|
<h1 style="display: flex; align-items: center;">
|
|
|
|
<svg style="width:36px;height:36px;margin-right:6px;" viewBox="0 0 32 32">
|
|
|
|
<rect style="fill:#003FFF" x="6" y="22" width="8" height="4"/>
|
|
|
|
<rect style="fill:#003FFF" x="14" y="14" width="4" height="8"/>
|
|
|
|
<rect style="fill:#003FFF" x="18" y="10" width="4" height="8"/>
|
|
|
|
<rect style="fill:#003FFF" x="22" y="6" width="8" height="4"/>
|
|
|
|
</svg>
|
2023-04-23 21:32:52 +02:00
|
|
|
<span id="head">WLED Custom Palette Editor</span>
|
2023-04-08 20:02:49 +02:00
|
|
|
</h1>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div id="parent-container">
|
|
|
|
<div id="gradient-box"></div>
|
|
|
|
</div>
|
|
|
|
<div style="display: flex; justify-content: center;">
|
2023-04-23 21:32:52 +02:00
|
|
|
<div id="palettes" class="palettesMain">
|
|
|
|
<div id="palTop">
|
|
|
|
Currently in use custom palettes
|
|
|
|
</div>
|
2023-04-08 20:02:49 +02:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div style="display: flex; justify-content: center;">
|
|
|
|
<div id="info">
|
2023-04-25 14:27:33 +02:00
|
|
|
Click on the gradient to add new color slider then the colored box below the slider to change its color.<br>
|
|
|
|
Click the red box below indicator (and confirm) to delete.<br>
|
|
|
|
Once finished click the arrow icon to upload into desired slot.<br>
|
|
|
|
To edit existing palette click pencil icon.
|
2023-04-08 20:02:49 +02:00
|
|
|
</div>
|
2023-04-12 09:15:38 +02:00
|
|
|
</div>
|
2023-04-14 18:33:03 +02:00
|
|
|
|
2023-04-08 20:02:49 +02:00
|
|
|
</body>
|
|
|
|
|
|
|
|
<script type="text/javascript">
|
2023-04-09 14:18:22 +02:00
|
|
|
//global variables
|
2023-04-08 20:02:49 +02:00
|
|
|
var gradientBox = gId('gradient-box');
|
2023-04-09 14:18:22 +02:00
|
|
|
var cpalc = -1;
|
2023-04-08 20:02:49 +02:00
|
|
|
var pxCol = {};
|
|
|
|
var tCol = {};
|
|
|
|
var rect = gradientBox.getBoundingClientRect();
|
|
|
|
var gradientLength = rect.width;
|
|
|
|
var mOffs = Math.round((gradientLength / 256) / 2) - 5;
|
2023-04-23 21:32:52 +02:00
|
|
|
var paletteArray = []; //Holds the palettes after load.
|
|
|
|
var svgSave = '<svg style="width:25px;height:25px" viewBox="0 0 24 24"><path fill=#fff d="M22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2A10,10 0 0,1 22,12M7,12L12,17V14H16V10H12V7L7,12Z"/></svg>'
|
|
|
|
var svgEdit = '<svg style="width:25px;height:25px" viewBox="0 0 24 24"><path fill=#fff d="M12,2C6.47,2 2,6.47 2,12C2,17.53 6.47,22 12,22C17.53,22 22,17.53 22,12C22,6.47 17.53,2 12,2M15.1,7.07C15.24,7.07 15.38,7.12 15.5,7.23L16.77,8.5C17,8.72 17,9.07 16.77,9.28L15.77,10.28L13.72,8.23L14.72,7.23C14.82,7.12 14.96,7.07 15.1,7.07M13.13,8.81L15.19,10.87L9.13,16.93H7.07V14.87L13.13,8.81Z"/></svg>'
|
2023-04-08 20:02:49 +02:00
|
|
|
|
2023-04-14 18:33:03 +02:00
|
|
|
function recOf() {
|
2023-04-08 20:02:49 +02:00
|
|
|
rect = gradientBox.getBoundingClientRect();
|
|
|
|
gradientLength = rect.width;
|
|
|
|
mOffs = Math.round((gradientLength / 256) / 2) - 5;
|
|
|
|
}
|
|
|
|
|
2023-04-09 14:18:22 +02:00
|
|
|
//Initiation
|
|
|
|
getInfo();
|
2023-04-12 09:15:38 +02:00
|
|
|
window.addEventListener('load', chkW);
|
|
|
|
window.addEventListener('resize', chkW);
|
2023-04-09 14:18:22 +02:00
|
|
|
|
2023-04-08 20:02:49 +02:00
|
|
|
gradientBox.addEventListener("click", clikOnGradient);
|
2023-04-23 21:32:52 +02:00
|
|
|
|
2023-04-08 20:02:49 +02:00
|
|
|
//Sets start and stop, mandatory
|
|
|
|
addC(0);
|
|
|
|
addC(255);
|
|
|
|
|
|
|
|
updateGradient(); //Sets the gradient at startup
|
|
|
|
|
|
|
|
function clikOnGradient(e){
|
2023-04-12 09:15:38 +02:00
|
|
|
removeTrashcan(e);
|
2023-04-08 20:02:49 +02:00
|
|
|
addC(Math.round((e.offsetX/gradientLength)*256));
|
|
|
|
}
|
|
|
|
|
|
|
|
///////// Add a new colorMarker
|
2023-04-23 21:32:52 +02:00
|
|
|
function addC(truePos, thisColor = ''){
|
2023-04-08 20:02:49 +02:00
|
|
|
let position = -1;
|
|
|
|
let iExist = false;
|
|
|
|
const colorMarkers = gradientBox.querySelectorAll('.color-marker');
|
|
|
|
|
|
|
|
colorMarkers.forEach((colorMarker, i) => {
|
2023-04-14 18:33:03 +02:00
|
|
|
if (colorMarker.getAttribute("data-truepos") == truePos) {
|
|
|
|
iExist = true;
|
2023-04-08 20:02:49 +02:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2023-04-14 18:33:03 +02:00
|
|
|
if (colorMarkers.length > 17) iExist = true;
|
|
|
|
if (iExist) return; // Exit the function early if iExist is true
|
2023-04-08 20:02:49 +02:00
|
|
|
|
2023-04-14 18:33:03 +02:00
|
|
|
if (truePos > 0 && truePos < 255) {
|
2023-04-08 20:02:49 +02:00
|
|
|
//calculate first available > 0
|
|
|
|
for (var i = 1; i <= 16 && position < 1; i++) {
|
2023-04-14 18:33:03 +02:00
|
|
|
if (!gId("colorMarker"+i)) {
|
2023-04-08 20:02:49 +02:00
|
|
|
position = i;
|
2023-04-14 18:33:03 +02:00
|
|
|
}
|
2023-04-08 20:02:49 +02:00
|
|
|
}
|
2023-04-14 18:33:03 +02:00
|
|
|
} else{
|
2023-04-08 20:02:49 +02:00
|
|
|
position = truePos;
|
|
|
|
}
|
2023-04-23 21:32:52 +02:00
|
|
|
if (thisColor == ''){
|
|
|
|
thisColor = `#${(Math.random() * 0xFFFFFF << 0).toString(16).padStart(6, '0')}`;// set random color as default
|
|
|
|
}
|
2023-04-08 20:02:49 +02:00
|
|
|
|
|
|
|
const colorMarker = cE('span'); // create a marker for the color position
|
|
|
|
colorMarker.className = 'color-marker';
|
|
|
|
colorMarker.id = 'colorMarker' + position.toString();
|
|
|
|
colorMarker.setAttribute("data-truepos", truePos); //Used to always have a true position no matter what screen or percentage we use
|
|
|
|
colorMarker.setAttribute("data-truecol", thisColor); //Used to hold the color of the position in the gradient connected to a true position
|
|
|
|
colorMarker.setAttribute("data-offset", mOffs);
|
|
|
|
colorMarker.addEventListener('click', stopFurtherProp); //Added to prevent the gradient click to fire when covered by a marker
|
|
|
|
colorMarker.style.left = `${Math.round((gradientLength / 256) * truePos)+mOffs}px`;
|
|
|
|
|
|
|
|
const colorPicker = cE('input');
|
|
|
|
colorPicker.type = 'color';
|
|
|
|
colorPicker.value = thisColor;
|
|
|
|
colorPicker.className = 'color-picker';
|
|
|
|
colorPicker.id = 'colorPicker' + position.toString();
|
|
|
|
colorPicker.addEventListener('input', updateGradient);
|
|
|
|
colorPicker.addEventListener('click',cpClk)
|
|
|
|
|
|
|
|
const colorPickerMarker = cE('span'); // create a marker for the color position
|
|
|
|
colorPickerMarker.className = 'color-picker-marker';
|
|
|
|
colorPickerMarker.id = 'colorPickerMarker' + position.toString();
|
|
|
|
colorPickerMarker.addEventListener('click', colClk);
|
|
|
|
colorPickerMarker.style.left = colorMarker.style.left;
|
|
|
|
colorPicker.style.left = colorMarker.style.left;
|
|
|
|
|
2023-04-12 09:15:38 +02:00
|
|
|
const deleteMarker = cE('span'); // create a delete marker for the color position
|
2023-04-14 18:33:03 +02:00
|
|
|
if (position > 0 && position < 255) {
|
2023-04-08 20:02:49 +02:00
|
|
|
deleteMarker.className = 'delete-marker';
|
|
|
|
deleteMarker.id = 'deleteMarker' + position.toString();
|
|
|
|
deleteMarker.addEventListener('click', (e) => {
|
|
|
|
deleteColor(e);
|
2023-04-14 18:33:03 +02:00
|
|
|
});
|
|
|
|
deleteMarker.style.left = colorMarker.style.left
|
2023-04-08 20:02:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
colorMarker.style.backgroundColor = colorPicker.value; // set marker color to match color picker
|
|
|
|
colorPickerMarker.style.backgroundColor = colorPicker.value;
|
|
|
|
|
2023-04-09 16:49:41 +02:00
|
|
|
gradientBox.appendChild(colorPicker);
|
2023-04-08 20:02:49 +02:00
|
|
|
gradientBox.appendChild(colorMarker);
|
|
|
|
gradientBox.appendChild(colorPickerMarker);
|
2023-04-14 18:33:03 +02:00
|
|
|
if (position != 0 && position != 255) gradientBox.appendChild(deleteMarker); // append the marker if not start or end
|
2023-04-08 20:02:49 +02:00
|
|
|
//make markers slidable IF they are not the first or last slider
|
2023-04-14 18:33:03 +02:00
|
|
|
if (position > 0 && position < 255) makeMeDrag(gId(colorMarker.id));
|
|
|
|
|
2023-04-08 20:02:49 +02:00
|
|
|
setTooltipMarker(gId(colorMarker.id));
|
|
|
|
|
|
|
|
updateGradient();
|
|
|
|
}
|
|
|
|
|
|
|
|
///////// Update Gradient
|
|
|
|
function updateGradient() {
|
|
|
|
const colorMarkers = gradientBox.querySelectorAll('.color-marker');
|
|
|
|
pxCol = {};
|
|
|
|
tCol = {}
|
|
|
|
colorMarkers.forEach((colorMarker, index) => {
|
|
|
|
const thisColorPicker = gId(colorMarkers[index].id.replace('colorMarker', 'colorPicker'));
|
|
|
|
const colorToSet = thisColorPicker.value;
|
|
|
|
gId(colorMarkers[index].id.replace('colorMarker', 'colorPickerMarker')).style.backgroundColor = colorToSet;
|
|
|
|
colorMarkers[index].style.backgroundColor = colorToSet;
|
|
|
|
colorMarkers[index].setAttribute("data-truecol", colorToSet);
|
|
|
|
const tPos = colorMarkers[index].getAttribute("data-truepos");
|
|
|
|
const gradientPos = Math.round((gradientLength / 256)*tPos);
|
|
|
|
pxCol[gradientPos] = colorToSet;
|
|
|
|
tCol[tPos] = colorToSet;
|
|
|
|
});
|
|
|
|
gradientString = 'linear-gradient(to right';
|
|
|
|
Object.entries(pxCol).forEach(([p, c]) => {
|
|
|
|
gradientString += `, ${c} ${p}px`;
|
|
|
|
});
|
|
|
|
gradientString += ')';
|
|
|
|
gradientBox.style.background = gradientString;
|
|
|
|
//gId("jsonstring").innerHTML = calcJSON();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function stopFurtherProp(e){
|
|
|
|
e.stopPropagation();
|
|
|
|
}
|
|
|
|
|
|
|
|
function colClk(e){
|
2023-04-12 09:15:38 +02:00
|
|
|
removeTrashcan(e)
|
2023-04-08 20:02:49 +02:00
|
|
|
e.stopPropagation();
|
|
|
|
let cp = gId(e.srcElement.id.replace("Marker",""));
|
|
|
|
cp.click();
|
|
|
|
}
|
|
|
|
|
|
|
|
function cpClk(e){
|
2023-04-12 09:15:38 +02:00
|
|
|
removeTrashcan(event)
|
2023-04-08 20:02:49 +02:00
|
|
|
e.stopPropagation();
|
|
|
|
}
|
2023-04-12 09:15:38 +02:00
|
|
|
|
2023-04-08 20:02:49 +02:00
|
|
|
//This neat little function makes any element draggable on the X-axis.
|
|
|
|
//Just call: makeMeDrag(myElement); And you are good to go.
|
|
|
|
function makeMeDrag(elmnt) {
|
|
|
|
var posNew = 0, mousePos = 0, mouseOffset = 0
|
|
|
|
|
|
|
|
//Set these to whatever you want to limit your movement to
|
|
|
|
var rect = gradientBox.getBoundingClientRect();
|
|
|
|
var maxX = rect.right; // maximum X coordinate
|
|
|
|
var minX = rect.left; // minimum X coordinate i.e. also offset from left of screen
|
|
|
|
var gradientLength = maxX - minX + 1;
|
|
|
|
|
|
|
|
elmnt.onmousedown = dragMouseDown;
|
|
|
|
|
|
|
|
function dragMouseDown(e) {
|
2023-04-12 09:15:38 +02:00
|
|
|
removeTrashcan(event)
|
2023-04-08 20:02:49 +02:00
|
|
|
e = e || window.event;
|
|
|
|
e.preventDefault();
|
|
|
|
// get the mouse cursor position at startup:
|
|
|
|
mousePos = e.clientX;
|
|
|
|
d.onmouseup = closeDragElement;
|
|
|
|
// call a function whenever the cursor moves:
|
|
|
|
d.onmousemove = elementDrag;
|
|
|
|
}
|
|
|
|
|
|
|
|
function elementDrag(e) {
|
|
|
|
e = e || window.event;
|
|
|
|
e.preventDefault();
|
|
|
|
// calculate the new cursor position:
|
|
|
|
posNew = mousePos - e.clientX;
|
|
|
|
mousePos = e.clientX;
|
|
|
|
mousePosInGradient = mousePos - (minX + 1)
|
|
|
|
|
|
|
|
truePos = Math.round((mousePosInGradient/gradientLength)*256);
|
|
|
|
oldTruePos = elmnt.getAttribute("data-truepos");
|
|
|
|
// set the element's new position if new position within min/max limits:
|
2023-04-14 18:33:03 +02:00
|
|
|
if (truePos > 0 && truePos < 255 && oldTruePos != truePos) {
|
|
|
|
if (truePos < 64) {
|
|
|
|
thisOffset = 0;
|
|
|
|
} else if (truePos > 192) {
|
|
|
|
thisOffset = 7;
|
|
|
|
} else {
|
|
|
|
thisOffset=3;
|
|
|
|
}
|
2023-04-08 20:02:49 +02:00
|
|
|
elmnt.style.left = (Math.round((gradientLength/256)*truePos)+mOffs) + "px";
|
|
|
|
gId(elmnt.id.replace('colorMarker', 'colorPickerMarker')).style.left = elmnt.style.left;
|
|
|
|
gId(elmnt.id.replace('colorMarker', 'deleteMarker')).style.left = elmnt.style.left;
|
|
|
|
gId(elmnt.id.replace('colorMarker', 'colorPicker')).style.left = elmnt.style.left;
|
|
|
|
elmnt.setAttribute("data-truepos", truePos);
|
|
|
|
setTooltipMarker(elmnt);
|
|
|
|
updateGradient();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function closeDragElement() {
|
|
|
|
/* stop moving when mouse button is released:*/
|
|
|
|
d.onmouseup = null;
|
|
|
|
d.onmousemove = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function setTooltipMarker(elmnt){
|
|
|
|
elmnt.setAttribute('title', `${elmnt.getAttribute("data-truepos")} : ${elmnt.getAttribute("data-truecol")}`)
|
|
|
|
}
|
|
|
|
|
|
|
|
function deleteColor(e) {
|
|
|
|
var trash = cE("div");
|
|
|
|
thisDeleteMarker = e.srcElement;
|
|
|
|
thisColorMarker = gId(thisDeleteMarker.id.replace("delete", "color"));
|
|
|
|
thisColorPickerMarker = gId(thisDeleteMarker.id.replace("delete", "colorPicker"));
|
|
|
|
thisColorPicker = gId(thisDeleteMarker.id.replace("deleteMarker", "colorPicker"));
|
|
|
|
renderOffsetX = 15 - 5;
|
|
|
|
renderX = e.srcElement.getBoundingClientRect().x - renderOffsetX;
|
|
|
|
renderY = e.srcElement.getBoundingClientRect().y + 13;
|
|
|
|
|
|
|
|
trash.id = "trash";
|
|
|
|
trash.innerHTML = '<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" width="30px" height="30px"><path style="fill:#880000; stroke: #888888; stroke-width: -2px;stroke-dasharray: 0.1, 8;" d="M9,3V4H4V6H5V19A2,2 0 0,0 7,21H17A2,2 0 0,0 19,19V6H20V4H15V3H9M7,6H17V19H7V6M9,8V17H11V8H9M13,8V17H15V8H13Z"/></svg>';
|
|
|
|
trash.style.position = "absolute";
|
|
|
|
trash.style.left = (renderX) + "px";
|
|
|
|
trash.style.top = (renderY) + "px";
|
|
|
|
d.body.appendChild(trash);
|
|
|
|
|
2023-04-14 18:33:03 +02:00
|
|
|
trash.addEventListener("click", (e)=>{
|
2023-04-08 20:02:49 +02:00
|
|
|
trash.parentNode.removeChild(trash);
|
|
|
|
thisDeleteMarker.parentNode.removeChild(thisDeleteMarker);
|
|
|
|
thisColorPickerMarker.parentNode.removeChild(thisColorPickerMarker);
|
|
|
|
thisColorMarker.parentNode.removeChild(thisColorMarker);
|
|
|
|
thisColorPicker.parentNode.removeChild(thisColorPicker);
|
|
|
|
updateGradient();
|
|
|
|
});
|
|
|
|
e.stopPropagation();
|
|
|
|
// Add event listener to close the trashcan on outside click
|
|
|
|
d.addEventListener("click", removeTrashcan);
|
|
|
|
e.stopPropagation();
|
|
|
|
}
|
|
|
|
|
|
|
|
function removeTrashcan(event) {
|
|
|
|
trash = gId("trash");
|
|
|
|
if (event.target != trash && trash) {
|
|
|
|
trash.parentNode.removeChild(trash);
|
|
|
|
d.removeEventListener("click", removeTrashcan);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-12 09:15:38 +02:00
|
|
|
function chkW() {
|
|
|
|
//Possibly add more code that recalculates the gradient... Massive job ;)
|
|
|
|
const wrap = gId('wrap');
|
|
|
|
const head = gId('head');
|
|
|
|
if (wrap.offsetWidth < 600) {
|
|
|
|
head.style.display = 'none';
|
|
|
|
} else {
|
|
|
|
head.style.display = 'inline';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-14 18:33:03 +02:00
|
|
|
function calcJSON() {
|
|
|
|
let rStr = '{"palette":['
|
2023-04-08 20:02:49 +02:00
|
|
|
Object.entries(tCol).forEach(([p, c]) => {
|
2023-04-14 18:33:03 +02:00
|
|
|
if (p > 0) rStr += ',';
|
2023-04-08 20:02:49 +02:00
|
|
|
rStr += `${p},${parseInt(c.slice(1, 3), 16)},${parseInt(c.slice(3, 5), 16)},${parseInt(c.slice(5, 7), 16)}`;
|
|
|
|
});
|
|
|
|
rStr += ']}';
|
|
|
|
return rStr;
|
|
|
|
}
|
|
|
|
|
2023-04-23 21:32:52 +02:00
|
|
|
function initiateUpload(idx) {
|
2023-04-14 18:33:03 +02:00
|
|
|
const data = calcJSON();
|
2023-04-23 21:32:52 +02:00
|
|
|
const fileName = `/palette${idx}.json`;
|
2023-04-14 18:33:03 +02:00
|
|
|
uploadJSON(data, fileName);
|
|
|
|
}
|
2023-04-08 20:02:49 +02:00
|
|
|
|
|
|
|
function uploadJSON(jsonString, fileName) {
|
2023-04-23 21:32:52 +02:00
|
|
|
//Some indication on "I'm working"
|
2023-04-09 16:49:41 +02:00
|
|
|
var req = new XMLHttpRequest();
|
|
|
|
var blob = new Blob([jsonString], {type: "application/json"});
|
2023-04-14 18:33:03 +02:00
|
|
|
req.addEventListener('load', ()=>{
|
2023-04-09 16:49:41 +02:00
|
|
|
console.log(this.responseText, ' - ', this.status)
|
2023-04-14 18:33:03 +02:00
|
|
|
localStorage.removeItem('wledPalx');
|
2023-04-23 21:32:52 +02:00
|
|
|
//setTimeout(()=>{
|
|
|
|
// ss.setAttribute('fill', '#fff');
|
|
|
|
//}, 1000);
|
|
|
|
//setTimeout(()=>{window.location.href='/';},2000);
|
|
|
|
window.location.href = '/'; //Guessing we want to return ASAP when we get confirmation save is done
|
2023-04-09 16:49:41 +02:00
|
|
|
});
|
2023-04-14 18:33:03 +02:00
|
|
|
req.addEventListener('error', (e)=>{
|
2023-04-09 16:49:41 +02:00
|
|
|
console.log('Error: ', e); console.log(' Status: ', this.status);
|
2023-04-23 21:32:52 +02:00
|
|
|
//Show some error notification for some time
|
2023-04-14 18:33:03 +02:00
|
|
|
setTimeout(()=>{
|
2023-04-23 21:32:52 +02:00
|
|
|
//Remove it when time has pased
|
2023-04-09 16:49:41 +02:00
|
|
|
}, 1000);
|
|
|
|
});
|
|
|
|
req.open("POST", "/upload");
|
|
|
|
var formData = new FormData();
|
|
|
|
formData.append("data", blob, fileName);
|
|
|
|
req.send(formData);
|
|
|
|
return false;
|
2023-04-08 20:02:49 +02:00
|
|
|
}
|
2023-04-09 14:18:22 +02:00
|
|
|
|
2023-04-12 09:15:38 +02:00
|
|
|
async function getInfo() {
|
|
|
|
hst = location.host;
|
|
|
|
if (hst.length > 0 ){
|
|
|
|
try {
|
|
|
|
var arr = [];
|
|
|
|
const response = await fetch('http://'+hst+'/json/info');
|
|
|
|
const json = await response.json();
|
|
|
|
cpalc = json.cpalcount;
|
2023-04-23 21:32:52 +02:00
|
|
|
fetchPalettes(cpalc-1);
|
2023-04-12 09:15:38 +02:00
|
|
|
console.log('cpalc: ', cpalc);
|
2023-04-23 21:32:52 +02:00
|
|
|
console.log(paletteArray);
|
2023-04-12 09:15:38 +02:00
|
|
|
} catch (error) {
|
|
|
|
console.error(error);
|
|
|
|
}
|
2023-04-14 18:33:03 +02:00
|
|
|
} else {
|
2023-04-12 09:15:38 +02:00
|
|
|
console.error('cannot identify host');
|
2023-04-09 14:18:22 +02:00
|
|
|
}
|
|
|
|
}
|
2023-04-23 21:32:52 +02:00
|
|
|
|
|
|
|
async function fetchPalettes(lastPal) {
|
|
|
|
paletteArray.length = 0;
|
|
|
|
for (let i = 0; i <= lastPal; i++) {
|
|
|
|
const url = `http://${hst}/palette${i}.json`;
|
|
|
|
try {
|
|
|
|
const response = await fetch(url);
|
|
|
|
const json = await response.json();
|
|
|
|
paletteArray.push(json);
|
|
|
|
} catch (error) {
|
|
|
|
console.error(`Error fetching JSON from ${url}: `, error);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
generatePaletteDivs();
|
|
|
|
}
|
|
|
|
|
|
|
|
function generatePaletteDivs() {
|
2023-04-25 13:02:09 +02:00
|
|
|
const palettesDiv = document.getElementById("palettes");
|
|
|
|
const paletteDivs = Array.from(palettesDiv.children).filter((child) => {
|
|
|
|
return child.id.match(/^palette\d$/); // match only elements with id starting with "palette" followed by a single digit
|
|
|
|
});
|
|
|
|
if (paletteArray.length < 10){
|
|
|
|
//Room for one more :)
|
|
|
|
paletteArray.push({"palette":[0,70,70,70,255,70,70,70]});
|
2023-04-23 21:32:52 +02:00
|
|
|
}
|
|
|
|
|
2023-04-25 13:02:09 +02:00
|
|
|
for (const div of paletteDivs) {
|
|
|
|
palettesDiv.removeChild(div); // remove each div that matches the above selector
|
2023-04-23 21:32:52 +02:00
|
|
|
}
|
|
|
|
|
2023-04-25 13:02:09 +02:00
|
|
|
for (let i = 0; i < paletteArray.length; i++) {
|
|
|
|
const palette = paletteArray[i];
|
|
|
|
const paletteDiv = document.createElement("div");
|
|
|
|
paletteDiv.id = `palette${i}`;
|
|
|
|
paletteDiv.classList.add("palette");
|
|
|
|
paletteDiv.dataset.colarray = JSON.stringify(palette.palette);
|
|
|
|
|
|
|
|
const gradientDiv = document.createElement("div");
|
|
|
|
gradientDiv.id = `paletteGradient${i}`
|
|
|
|
const buttonsDiv = document.createElement("div");
|
|
|
|
buttonsDiv.id = `buttonsDiv${i}`;
|
|
|
|
buttonsDiv.classList.add("buttonsDiv")
|
|
|
|
|
|
|
|
const sendSpan = document.createElement("span");
|
|
|
|
sendSpan.id = `sendSpan${i}`;
|
|
|
|
sendSpan.onclick = function() {initiateUpload(i)};
|
|
|
|
sendSpan.setAttribute('title', `Send current editor to slot ${i}`); // perhaps Save instead of Send?
|
|
|
|
sendSpan.innerHTML = svgSave;
|
|
|
|
sendSpan.classList.add("sendSpan")
|
|
|
|
const editSpan = document.createElement("span");
|
|
|
|
editSpan.id = `editSpan${i}`;
|
|
|
|
editSpan.onclick = function() {loadForEdit(i)};
|
|
|
|
editSpan.setAttribute('title', `Copy slot ${i} palette to editor`);
|
|
|
|
editSpan.innerHTML = svgEdit;
|
|
|
|
editSpan.classList.add("editSpan")
|
|
|
|
|
|
|
|
gradientDiv.classList.add("paletteGradients");
|
|
|
|
let gradientColors = "";
|
|
|
|
for (let j = 0; j < palette.palette.length; j += 2) {
|
|
|
|
const position = palette.palette[j];
|
2023-04-26 14:45:39 +02:00
|
|
|
if (typeof(palette.palette[j+1]) === "string") {
|
2023-04-25 13:02:09 +02:00
|
|
|
gradientColors += `#${palette.palette[j+1]} ${position/255*100}%, `;
|
|
|
|
} else {
|
|
|
|
const red = palette.palette[j + 1];
|
|
|
|
const green = palette.palette[j + 2];
|
|
|
|
const blue = palette.palette[j + 3];
|
|
|
|
gradientColors += `rgba(${red}, ${green}, ${blue}, 1) ${position/255*100}%, `;
|
|
|
|
j += 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
gradientColors = gradientColors.slice(0, -2); // remove the last comma and space
|
|
|
|
gradientDiv.style.backgroundImage = `linear-gradient(to right, ${gradientColors})`;
|
|
|
|
paletteDiv.className = "palGradientParent";
|
|
|
|
buttonsDiv.appendChild(sendSpan);
|
|
|
|
if(i<cpalc){
|
|
|
|
buttonsDiv.appendChild(editSpan); //Dont offer to edit the empty spot
|
|
|
|
}
|
|
|
|
paletteDiv.appendChild(gradientDiv);
|
|
|
|
paletteDiv.appendChild(buttonsDiv);
|
|
|
|
|
|
|
|
palettesDiv.appendChild(paletteDiv);
|
|
|
|
}
|
2023-04-23 21:32:52 +02:00
|
|
|
}
|
2023-04-25 13:02:09 +02:00
|
|
|
|
|
|
|
function loadForEdit(i){
|
|
|
|
console.log("Lets edit no: ", i);
|
|
|
|
document.querySelectorAll('input[id^="colorPicker"]').forEach((input) => {
|
|
|
|
input.parentNode.removeChild(input);
|
|
|
|
});
|
|
|
|
document.querySelectorAll('span[id^="colorMarker"], span[id^="colorPickerMarker"], span[id^="deleteMarker"]').forEach((span) => {
|
|
|
|
span.parentNode.removeChild(span);
|
|
|
|
});
|
|
|
|
|
|
|
|
let colArray = JSON.parse(gId(`palette${i}`).getAttribute("data-colarray"));
|
|
|
|
|
|
|
|
for (let j = 0; j < colArray.length; j += 2) {
|
|
|
|
const position = colArray[j];
|
2023-04-25 14:27:33 +02:00
|
|
|
let hex;
|
2023-04-25 13:02:09 +02:00
|
|
|
if (typeof(colArray[j+1]) === "string") {
|
2023-04-25 14:27:33 +02:00
|
|
|
hex = `#${colArray[j+1]}`;
|
2023-04-25 13:02:09 +02:00
|
|
|
} else {
|
|
|
|
const red = colArray[j + 1];
|
|
|
|
const green = colArray[j + 2];
|
|
|
|
const blue = colArray[j + 3];
|
2023-04-25 14:27:33 +02:00
|
|
|
hex = rgbToHex(red, green, blue);
|
2023-04-25 13:02:09 +02:00
|
|
|
j += 2;
|
|
|
|
}
|
|
|
|
console.log(position, hex)
|
|
|
|
addC(position, hex);
|
|
|
|
}
|
2023-04-23 21:32:52 +02:00
|
|
|
}
|
|
|
|
|
2023-04-25 13:02:09 +02:00
|
|
|
function rgbToHex(r, g, b) {
|
|
|
|
const hex = ((r << 16) | (g << 8) | b).toString(16);
|
|
|
|
return "#" + "0".repeat(6 - hex.length) + hex;
|
|
|
|
}
|
2023-04-23 21:32:52 +02:00
|
|
|
|
|
|
|
function getLocalStorageData(){
|
|
|
|
// Retrieve the "wledPalx" JSON from local storage
|
|
|
|
const wledPalx = JSON.parse(localStorage.getItem('wledPalx'));
|
|
|
|
|
|
|
|
// Initialize an empty array to store the extracted arrays
|
|
|
|
const result = [];
|
|
|
|
|
|
|
|
// Loop through the "p" object in the "wledPalx" JSON
|
|
|
|
for (const key in wledPalx.p) {
|
|
|
|
if (wledPalx.p.hasOwnProperty(key)) {
|
|
|
|
// Check if the key is between 246 and 255
|
|
|
|
const numKey = parseInt(key, 10);
|
|
|
|
if (numKey >= 246 && numKey <= 255) {
|
|
|
|
// Replace the key with a new key that follows the mapping
|
|
|
|
const newKey = 255 - numKey;
|
|
|
|
// Add the array to the result array with the new key as the index
|
|
|
|
result[newKey] = wledPalx.p[key];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// The "result" array now contains arrays with the new keys
|
|
|
|
console.log(result);
|
|
|
|
}
|
2023-04-08 20:02:49 +02:00
|
|
|
</script>
|
|
|
|
|
2023-04-23 21:32:52 +02:00
|
|
|
|
|
|
|
|