Ledmaps improvements
index.js: - add global ledmap variable - updateLen conditional draw parameter - draw black out not mapped json.cpp: - add "ledmap" in (de)serializeState (not info) - use loadedLedmap wled.cpp/h: - loadLedMap is boolean, use loadedLedmap for ledmap - show * password liveviewws2D: colorAmp settings2D: add id and name, change max to 255
This commit is contained in:
@@ -37,6 +37,7 @@ var hol = [
|
||||
[0,0,1,1,"https://initiate.alphacoders.com/download/wallpaper/1198800/images/jpg/2522807481585600"] // new year
|
||||
];
|
||||
var ctx = null; // WLEDMM
|
||||
var ledmap = -1; //WLEDMM
|
||||
|
||||
function handleVisibilityChange() {if (!d.hidden && new Date () - lastUpdate > 3000) requestJson();}
|
||||
function sCol(na, col) {d.documentElement.style.setProperty(na, col);}
|
||||
@@ -709,7 +710,6 @@ function populateSegments(s)
|
||||
segCount = 0; lowestUnused = 0; lSeg = 0;
|
||||
|
||||
for (var inst of (s.seg||[])) {
|
||||
console.log("inst", inst);
|
||||
segCount++;
|
||||
|
||||
let i = parseInt(inst.id);
|
||||
@@ -828,7 +828,7 @@ function populateSegments(s)
|
||||
resetUtil(noNewSegs);
|
||||
if (gId('selall')) gId('selall').checked = true;
|
||||
for (var i = 0; i <= lSeg; i++) {
|
||||
updateLen(i);
|
||||
updateLen(i, false);
|
||||
updateTrail(gId(`seg${i}bri`));
|
||||
gId(`segr${i}`).style.display = "none";
|
||||
if (!gId(`seg${i}sel`).checked && gId('selall')) gId('selall').checked = false; // uncheck if at least one is unselected.
|
||||
@@ -839,13 +839,14 @@ function populateSegments(s)
|
||||
|
||||
if (Array.isArray(li.maps) && li.maps.length>0) { //WLEDMM >0 instead of 1 to show also first ledmap. Attention: WLED AC has isM check, in MM Matrices are supported so do not check on isM
|
||||
let cont = `Ledmap: <select class="sel-sg" onchange="requestJson({'ledmap':parseInt(this.value)})">`; //WLEDMM remove <option value="" selected>Unchanged</option>
|
||||
for (const k of (li.maps||[])) cont += `<option value="${k}"${(i>0 && li.ledmap==k)?" selected":""}>${k==0?'Default':'ledmap'+k+'.json'}</option>`; //WLEDMM set ledmap selected
|
||||
for (const k of (li.maps||[])) cont += `<option value="${k}"${(i>0 && ledmap==k)?" selected":""}>${k==0?'Default':'ledmap'+k+'.json'}</option>`; //WLEDMM set ledmap selected
|
||||
cont += "</select></div>";
|
||||
gId("ledmap").innerHTML = cont;
|
||||
gId("ledmap").classList.remove('hide');
|
||||
} else {
|
||||
gId("ledmap").classList.add('hide');
|
||||
}
|
||||
if (isM) drawSegments(); //WLEDMM
|
||||
}
|
||||
|
||||
function populateEffects()
|
||||
@@ -1074,9 +1075,8 @@ function toggleBubble(e)
|
||||
}
|
||||
|
||||
// updates segment length upon input of segment values
|
||||
function updateLen(s)
|
||||
function updateLen(s, draw=true) //WLEDMM conditonally draw segment visualisation
|
||||
{
|
||||
console.log("updateLen", s);
|
||||
if (!gId(`seg${s}s`)) return;
|
||||
var start = parseInt(gId(`seg${s}s`).value);
|
||||
var stop = parseInt(gId(`seg${s}e`).value) + (cfg.comp.seglen?start:0);
|
||||
@@ -1146,14 +1146,14 @@ function updateLen(s)
|
||||
if (isM && start >= mw*mh) out += " [strip]";
|
||||
|
||||
gId(`seg${s}len`).innerHTML = out;
|
||||
if (isM) drawSegments(); //WLEDMM draw new segment graphic if something changes in a segment
|
||||
|
||||
if (draw && isM) drawSegments(); //WLEDMM draw new segment visualization if something changes in a segment
|
||||
}
|
||||
|
||||
//WLEDMM
|
||||
function drawSegments() {
|
||||
|
||||
if (!ctx) {
|
||||
console.log("init", window.innerWidth);
|
||||
//WLEDMM: add canvas, initialize and set UI
|
||||
var canvas = gId("canvas");
|
||||
canvas.hidden = false;
|
||||
@@ -1161,23 +1161,34 @@ function drawSegments() {
|
||||
}
|
||||
ctx.canvas.width = ctx.canvas.parentElement.offsetWidth > 800?800:300; //Mobile and non pc mode gets 300, pc 800
|
||||
|
||||
var px, py, pw, ph;
|
||||
var topLeftX, topLeftY;
|
||||
|
||||
var space=0; // space between panels + margin
|
||||
function initSegmentVars(p) {
|
||||
px = parseInt(gId("seg"+p+"s").value); //first led x
|
||||
if (!gId("seg"+p+"sY")) return false; //no draw for 1D segments (yet)
|
||||
py = parseInt(gId("seg"+p+"sY").value); //first led y
|
||||
pw = parseInt(gId("seg"+p+"e").value - gId("seg"+p+"s").value); //width
|
||||
ph = parseInt(gId("seg"+p+"eY").value - gId("seg"+p+"sY").value); //height
|
||||
// console.log("sergment", p, px, py, pw, ph);
|
||||
topLeftX = px*ppL + space; //left margin
|
||||
topLeftY = py*ppL + space; //top margin
|
||||
// console.log("rect", p, topLeftX, topLeftY, pw*ppL, ph*ppL);
|
||||
return true;
|
||||
}
|
||||
|
||||
//calc max height and width
|
||||
var maxWidth = 0;
|
||||
var maxHeight = 0;
|
||||
for (let p=0; p<gId("segcont").children.length; p++) {
|
||||
var px = parseInt(gId("seg"+p+"s").value); //first led x
|
||||
if (!gId("seg"+p+"sY")) break; //no draw for 1D segments (yet)
|
||||
var py = parseInt(gId("seg"+p+"sY").value); //first led y
|
||||
var pw = parseInt(gId("seg"+p+"e").value - gId("seg"+p+"s").value); //width
|
||||
var ph = parseInt(gId("seg"+p+"eY").value - gId("seg"+p+"sY").value); //height
|
||||
|
||||
if (!initSegmentVars(p)) break;
|
||||
maxWidth = Math.max(maxWidth, px + pw);
|
||||
maxHeight = Math.max(maxHeight, py + ph);
|
||||
}
|
||||
|
||||
ctx.canvas.height = ctx.canvas.width / maxWidth * maxHeight;
|
||||
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
|
||||
var space=0; // space between panels + margin
|
||||
var ppL = (ctx.canvas.width - space * 2) / maxWidth; //pixels per led
|
||||
// console.log("dim", ctx.canvas.width , maxWidth, ctx.canvas.height , maxHeight, ppL);
|
||||
|
||||
@@ -1191,17 +1202,8 @@ function drawSegments() {
|
||||
for (let p=0; p<gId("segcont").children.length; p++) {
|
||||
// console.log(gId("P"+p+"X").value, gId("P"+p+"Y").value, gId("P"+p+"W").value, gId("P"+p+"H").value, gId("P"+p+"B").value, gId("P"+p+"R").value, gId("P"+p+"V").value, gId("P"+p+"S").checked);
|
||||
|
||||
var px = parseInt(gId("seg"+p+"s").value); //first led x
|
||||
if (!gId("seg"+p+"sY")) break; //no draw for 1D segments (yet)
|
||||
var py = parseInt(gId("seg"+p+"sY").value); //first led y
|
||||
var pw = parseInt(gId("seg"+p+"e").value - gId("seg"+p+"s").value); //width
|
||||
var ph = parseInt(gId("seg"+p+"eY").value - gId("seg"+p+"sY").value); //height
|
||||
if (!initSegmentVars(p)) break;
|
||||
|
||||
// console.log("sergment", p, px, py, pw, ph);
|
||||
|
||||
var topLeftX = px*ppL + space; //left margin
|
||||
var topLeftY = py*ppL + space; //top margin
|
||||
// console.log("rect", p, topLeftX, topLeftY, pw*ppL, ph*ppL);
|
||||
ctx.lineWidth = 3;
|
||||
ctx.strokeStyle="white";
|
||||
ctx.strokeRect(topLeftX, topLeftY, pw*ppL, ph*ppL); // add space between panels
|
||||
@@ -1278,35 +1280,58 @@ function drawSegments() {
|
||||
}
|
||||
}
|
||||
|
||||
ctx.font = '40px Arial';
|
||||
ctx.fillStyle = "orange";
|
||||
ctx.fillText(p, topLeftX + pw/2*ppL - 10, topLeftY + ph/2*ppL + 10);
|
||||
|
||||
ctx.font = '20px Arial';
|
||||
ctx.fillStyle = "white";
|
||||
var name = eJson.find((o)=>{return o.id==fx}).name;
|
||||
ctx.fillText(name, topLeftX + ppL, topLeftY + ph*ppL - 10);
|
||||
|
||||
} // for each segment
|
||||
|
||||
gId("MD").innerHTML = "☾ W*H=LC: " + maxWidth + " x " + maxHeight + " = " + maxWidth * maxHeight;
|
||||
|
||||
function post() {
|
||||
for (let p=0; p<gId("segcont").children.length; p++) {
|
||||
if (!initSegmentVars(p)) break;
|
||||
|
||||
ctx.font = '40px Arial';
|
||||
ctx.fillStyle = "orange";
|
||||
ctx.fillText(p, topLeftX + pw/2*ppL - 10, topLeftY + ph/2*ppL + 10);
|
||||
|
||||
ctx.font = '20px Arial';
|
||||
ctx.fillStyle = "white";
|
||||
var name = eJson.find((o)=>{return o.id==fx}).name;
|
||||
ctx.fillText(name, topLeftX + ppL, topLeftY + ph*ppL - 10);
|
||||
}
|
||||
}
|
||||
|
||||
//draw the ledmap
|
||||
if (lastinfo.ledmap>0 && ctx) {
|
||||
if (ledmap>0 && ctx) {
|
||||
// console.log("Before fetch ledmap ", lastinfo.ledmap);
|
||||
fetchAndExecute((loc?`http://${locip}`:'.') + "/", "ledmap"+lastinfo.ledmap+".json" , function(text) {
|
||||
fetchAndExecute((loc?`http://${locip}`:'.') + "/", "ledmap"+ledmap+".json" , function(text) {
|
||||
var noMap = [];
|
||||
ledmapJson = JSON.parse(text);
|
||||
var counter = 0;
|
||||
for (let i=0;i<ledmapJson["map"].length;i++) {
|
||||
ctx.font = parseInt(ppL/3) + 'px Arial';
|
||||
ctx.fillStyle = "white";
|
||||
x = ledmapJson["map"][i]%maxWidth;
|
||||
y = parseInt(ledmapJson["map"][i]/maxWidth);
|
||||
ctx.fillText(counter, topLeftX + ppL/2 + x*ppL-ppL*0.3, topLeftY + ppL/2 + y * ppL);
|
||||
counter++;
|
||||
let mapIndex = ledmapJson["map"][i];
|
||||
if (mapIndex != -1) {
|
||||
ctx.font = parseInt(ppL/3) + 'px Arial';
|
||||
ctx.fillStyle = "white";
|
||||
x = mapIndex%maxWidth;
|
||||
y = parseInt(mapIndex/maxWidth);
|
||||
ctx.fillText(counter, topLeftX + ppL/2 + x*ppL-ppL*0.3, topLeftY + ppL/2 + y * ppL);
|
||||
counter++;
|
||||
}
|
||||
else
|
||||
noMap.push(i);
|
||||
}
|
||||
for (let i=0;i<noMap.length;i++) {
|
||||
x = noMap[i]%maxWidth;
|
||||
y = parseInt(noMap[i]/maxWidth);
|
||||
ctx.fillStyle = "black";
|
||||
ctx.beginPath();
|
||||
ctx.arc(topLeftX + ppL/2 + x*ppL, topLeftY + ppL/2 + y * ppL, ppL*0.4, 0, 2 * Math.PI);
|
||||
ctx.fill();
|
||||
}
|
||||
post();
|
||||
});
|
||||
}
|
||||
else
|
||||
post();
|
||||
}
|
||||
|
||||
// updates background color of currently selected preset
|
||||
@@ -1456,6 +1481,7 @@ function makeWS() {
|
||||
clearErrorToast();
|
||||
gId('connind').style.backgroundColor = "var(--c-l)";
|
||||
// json object should contain json.info AND json.state (but may not)
|
||||
// console.log("makeWS onmessage", json); //WLEDMM Debug
|
||||
var i = json.info;
|
||||
if (i) {
|
||||
parseInfo(i);
|
||||
@@ -1496,6 +1522,8 @@ function readState(s,command=false)
|
||||
tr = s.transition;
|
||||
gId('tt').value = tr/10;
|
||||
|
||||
ledmap = s.ledmap; //WLEDMM
|
||||
|
||||
populateSegments(s);
|
||||
var selc=0;
|
||||
var sellvl=0; // 0: selc is invalid, 1: selc is mainseg, 2: selc is first selected
|
||||
@@ -1736,10 +1764,12 @@ function requestJson(command=null)
|
||||
};
|
||||
|
||||
if (useWs) {
|
||||
// console.log("requestJson ws.send", command); //WLEDMM Debug
|
||||
ws.send(req?req:'{"v":true}');
|
||||
return;
|
||||
}
|
||||
|
||||
// console.log("requestJson url fetch", url, type); //WLEDMM Debug
|
||||
fetch(url, {
|
||||
method: type,
|
||||
headers: {
|
||||
@@ -1759,6 +1789,7 @@ function requestJson(command=null)
|
||||
gId('connind').style.backgroundColor = "var(--c-g)";
|
||||
if (!json) { showToast('Empty response', true); return; }
|
||||
if (json.success) return;
|
||||
// console.log("requestJson url return", json); //WLEDMM Debug
|
||||
if (json.info) {
|
||||
let i = json.info;
|
||||
// append custom palettes (when loading for the 1st time)
|
||||
@@ -3142,9 +3173,12 @@ function togglePcMode(fromB = false)
|
||||
sCol('--bh', gId('bot').clientHeight + "px");
|
||||
_C.style.width = (pcMode)?'100%':'400%';
|
||||
lastw = wW;
|
||||
//WLEDMM
|
||||
gId("canvas").width = gId("canvas").parentElement.offsetWidth > 800?800:300; //WLEDMM Mobile and non pc mode gets 300, pc 800
|
||||
drawSegments(); //WLEDMM
|
||||
|
||||
//WLEDMM resize segment visualization
|
||||
if (isM) {
|
||||
gId("canvas").width = gId("canvas").parentElement.offsetWidth > 800?800:300; //WLEDMM Mobile and non pc mode gets 300, pc 800
|
||||
drawSegments();
|
||||
}
|
||||
}
|
||||
|
||||
function mergeDeep(target, ...sources)
|
||||
|
||||
@@ -50,9 +50,12 @@
|
||||
let lOf = Math.floor((c.width - pPL*mW)/2); //left offeset (to center matrix)
|
||||
var i = 6;
|
||||
ctx.clearRect(0, 0, c.width, c.height); //WLEDMM
|
||||
function colorAdjust(color) {return 55+150*color/255;} //WLEDMM in range 55 - 205
|
||||
function colorAmp(color) {
|
||||
if (color == 0) return 0;
|
||||
return 25+225*color/255;
|
||||
} //WLEDMM in range 55 - 205
|
||||
for (y=0.5;y<mH;y++) for (x=0.5; x<mW; x++) {
|
||||
ctx.fillStyle = `rgb(${colorAdjust(leds[i])},${colorAdjust(leds[i+1])},${colorAdjust(leds[i+2])})`;
|
||||
ctx.fillStyle = `rgb(${colorAmp(leds[i])},${colorAmp(leds[i+1])},${colorAmp(leds[i+2])})`;
|
||||
ctx.beginPath();
|
||||
ctx.arc(x*pPL+lOf, y*pPL, pPL*0.4, 0, 2 * Math.PI);
|
||||
ctx.fill();
|
||||
|
||||
@@ -72,6 +72,7 @@
|
||||
if (p.children.length >= maxPanels) return;
|
||||
var pw = parseInt(d.Sf.PW.value);
|
||||
var ph = parseInt(d.Sf.PH.value);
|
||||
//WLEDMM: change name to id
|
||||
let b = `<div id="pnl${i}"><hr class="sml">Panel ${i}<br>
|
||||
1<sup>st</sup> LED: <select id="P${i}B" name="P${i}B" oninput="draw()">
|
||||
<option value="0">Top</option>
|
||||
@@ -84,10 +85,10 @@ Orientation: <select id="P${i}V" name="P${i}V" oninput="draw()">
|
||||
<option value="0">Horizontal</option>
|
||||
<option value="1">Vertical</option>
|
||||
</select><br>
|
||||
Serpentine: <input id="P${i}S" type="checkbox" name="P${i}S" onclick="draw()"><br>
|
||||
Dimensions (WxH): <input id="P${i}W" name="P${i}W" type="number" min="1" max="128" value="${pw}" oninput="draw()"> x <input id="P${i}H" name="P${i}H" type="number" min="1" max="128" value="${ph}" oninput="draw()"><br>
|
||||
Offset X:<input id="P${i}X" name="P${i}X" type="number" min="0" max="256" value="0" oninput="draw()">
|
||||
Y:<input id="P${i}Y" name="P${i}Y" type="number" min="0" max="256" value="0" oninput="draw()"><br><i>(offset from top-left corner in # LEDs)</i>
|
||||
Serpentine: <input id="P${i}S" name="P${i}S" type="checkbox" onclick="draw()"><br>
|
||||
Dimensions (WxH): <input id="P${i}W" name="P${i}W" type="number" min="1" max="255" value="${pw}" oninput="draw()"> x <input id="P${i}H" name="P${i}H" type="number" min="1" max="255" value="${ph}" oninput="draw()"><br>
|
||||
Offset X:<input id="P${i}X" name="P${i}X" type="number" min="0" max="255" value="0" oninput="draw()">
|
||||
Y:<input id="P${i}Y" name="P${i}Y" type="number" min="0" max="255" value="0" oninput="draw()"><br><i>(offset from top-left corner in # LEDs)</i>
|
||||
</div>`;
|
||||
p.insertAdjacentHTML("beforeend", b);
|
||||
}
|
||||
@@ -364,7 +365,7 @@ Y:<input id="P${i}Y" name="P${i}Y" type="number" min="0" max="256" value="0" oni
|
||||
<br>
|
||||
<hr class="sml">
|
||||
<h3 id="title">Matrix Generator</h3>
|
||||
Panel dimensions (WxH): <input name="PW" type="number" min="1" max="128" value="8" oninput="fieldChange()"> x <input name="PH" type="number" min="1" max="128" value="8" oninput="fieldChange()"><br>
|
||||
Panel dimensions (WxH): <input name="PW" type="number" min="1" max="255" value="8" oninput="fieldChange()"> x <input name="PH" type="number" min="1" max="255" value="8" oninput="fieldChange()"><br>
|
||||
Horizontal panels: <input name="MPH" type="number" min="1" max="8" value="1" oninput="fieldChange()">
|
||||
Vertical panels: <input name="MPV" type="number" min="1" max="8" value="1" oninput="fieldChange()"><br>
|
||||
<div id="panelOrientationBlock">
|
||||
@@ -397,8 +398,8 @@ Y:<input id="P${i}Y" name="P${i}Y" type="number" min="0" max="256" value="0" oni
|
||||
<br>
|
||||
<hr class="sml">
|
||||
☾<br>
|
||||
<canvas id="canvas"></canvas><br>
|
||||
<div id="MD"></div> <!-- Matrix dimensions -->
|
||||
<canvas id="canvas"></canvas><br> <!--WLEDMM panel visualization-->
|
||||
<div id="MD"></div> <!-- WLEDMM Matrix dimensions -->
|
||||
<br>
|
||||
<div id="advancedBlock">
|
||||
<i style="color:#fa0;">Can populate LED panel layout with pre-arranged matrix.<br>These values do not affect final layout.<br>WLEDMM: Populate will overwrite earlier saved panel layouts!</i><br>
|
||||
|
||||
Reference in New Issue
Block a user