100 lines
26 KiB
HTML
100 lines
26 KiB
HTML
<!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"> <title>
|
|
WLED Pixel Art Converter</title> <style>
|
|
.box{border:2px solid #fff}body{font-family:Arial,sans-serif;background-color:#111}.top-part{width:600px;margin:0 auto}.container{max-width:100% -40px;border-radius:0;padding:20px;text-align:center}h1{font-size:2.3em;color:#ddd;margin:1px 0;font-family:Arial,sans-serif;line-height:.5}h2{font-size:1.1em;color:rgba(221,221,221,.61);margin:1px 0;font-family:Arial,sans-serif;line-height:.5;text-align:center}h3{font-size:.7em;color:rgba(221,221,221,.61);margin:1px 0;font-family:Arial,sans-serif;line-height:1.4;text-align:center;align-items:center;justify-content:center;display:flex}p{font-size:1em;color:#777;line-height:1.5;font-family:Arial,sans-serif}#fieldTable{font-size:1 em;color:#777;line-height:1;font-family:Arial,sans-serif}#scaleTable{font-size:1 em;color:#777;line-height:1;font-family:Arial,sans-serif}#drop-zone{display:block;width:100%-40px;border:3px dashed #ddd;border-radius:0;text-align:center;padding:20px;margin:0;cursor:pointer;font-family:Arial,sans-serif;font-size:15px;color:#777}#file-picker{display:none}.adaptiveTD{display:flex;flex-direction:row;flex-wrap:nowrap;align-items:center}.mainSelector{background-color:#222;color:#ddd;border:1px solid #333;margin-top:4px;margin-bottom:4px;padding:0 8px;height:28px;font-size:15px;border-radius:7px;flex-grow:1;display:flex;align-items:center;justify-content:center}.adaptiveSelector{background-color:#222;color:#ddd;border:1px solid #333;margin-top:4px;margin-bottom:4px;padding:0 8px;height:28px;font-size:15px;border-radius:7px;flex-grow:1;display:none}.segmentsDiv{width:36px;padding-left:5px}* input[type=range]{appearance:none;-moz-appearance:none;-webkit-appearance:none;flex-grow:1;padding:0;margin:4px 8px 4px 0;background-color:transparent;cursor:pointer;background:linear-gradient(to right,#bbb 50%,#333 50%);border-radius:7px}input[type=range]:focus{outline:0}input[type=range]::-webkit-slider-runnable-track{height:28px;cursor:pointer;background:0 0;border-radius:7px}input[type=range]::-webkit-slider-thumb{height:16px;width:16px;border-radius:50%;background:#fff;cursor:pointer;-webkit-appearance:none;margin-top:4px;border-radius:7px}input[type=range]::-moz-range-track{height:28px;background-color:rgba(0,0,0,0);border-radius:7px}input[type=range]::-moz-range-thumb{border:0 solid transparent;height:16px;width:16px;border-radius:7px;background:#fff}.rangeNumber{width:20px;vertical-align:middle}.fullTextField[type=text]{background-color:#222;border:1px solid #333;padding-inline-start:5px;margin-top:4px;margin-bottom:4px;height:24px;border-radius:0;font-family:Arial,sans-serif;font-size:15px;color:#ddd;border-radius:7px;flex-grow:1;display:flex;align-items:center;justify-content:center}.flxTFld{background-color:#222;border:1px solid #333;padding-inline-start:5px;height:24px;border-radius:0;font-family:Arial,sans-serif;font-size:15px;color:#ddd;border-radius:7px;flex-grow:1;display:flex;align-items:center;justify-content:center}* input[type=submit]{background-color:#222;border:1px solid #333;padding:.5em;width:100%;border-radius:24px;font-family:Arial,sans-serif;font-size:1.3em;color:#ddd}* button{background-color:#222;border:1px solid #333;padding-inline:5px;width:100%;border-radius:24px;font-family:Arial,sans-serif;font-size:1em;color:#ddd;display:flex;align-items:center;justify-content:center;cursor:pointer}#scaleDiv{display:flex;align-items:center;vertical-align:middle}textarea{grid-row:1/2;width:100%;height:200px;background-color:#222;border:1px solid #333;color:#ddd}.hide{display:none}.svg-icon{vertical-align:middle}#image-container{display:grid;grid-template-rows:1fr 1fr}#button-container{display:flex;padding-bottom:10px;padding-top:10px}.buttonclass{flex:1;padding-top:5px;padding-bottom:5px}.gap{width:10px}#submitConvert::before{content:"";display:inline-block;background-image:url('data:image/svg+xml;utf8, <svg style="width:24px;height:24px" viewBox="0 0 24 24" <path fill="currentColor" d="M12,6V9L16,5L12,1V4A8,8 0 0,0 4,12C4,13.57 4.46,15.03 5.24,16.26L6.7,14.8C6.25,13.97 6,13 6,12A6,6 0 0,1 12,6M18.76,7.74L17.3,9.2C17.74,10.04 18,11 18,12A6,6 0 0,1 12,18V15L8,19L12,23V20A8,8 0 0,0 20,12C20,10.43 19.54,8.97 18.76,7.74Z" /></svg>');width:36px;height:36px}#sizeDiv *{display:inline-block}.sizeInputFields{width:50px;background-color:#222;border:1px solid #333;padding-inline-start:5px;margin-top:-5px;height:24px;border-radius:7px;font-family:Arial,sans-serif;font-size:15px;color:#ddd}a:link{color:rgba(221,221,221,.61);background-color:transparent;text-decoration:none}a:visited{color:rgba(221,221,221,.61);background-color:transparent;text-decoration:none}a:hover{color:#ddd;background-color:transparent;text-decoration:none}a:active{color:rgba(221,221,221,.61);background-color:transparent;text-decoration:none}
|
|
</style> <link rel="shortcut icon"
|
|
href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAkNJREFUOE+lUstO21AUnHNsF0V+0EXVivAXfAe7qlL7EZEcQ5cQ8nCICbDJF7Trvhas6YbyDdBu2hSk7kihscK1fU91HRKKaFf1xhrP8ejMnCH850P/+v/cC2qcqw4gsGD3Hk/G23+bvSdw7nk1K887BeCQ4AGMAiEjcGaB7gndEfhRqdRQSC9ncQikAVisAWGBFggR5QvQ7UcTNd9mLvDdC2p2rhIN2G4U/vRbneyynzhps70oAPlhNPLjZna1v4/xVmtQHU8tzQXO3CCk4nrPD8MLN+6qd8ef8erwBKvH750XK1Xy4li9/fQFrw9PAGSDg8azuwJDN6jbuep7a+GFF3ezN0en5fDq8Qfn+UqVgjhW5bePpwCKwUHj6a2ACY7zrCdCC34UjrzutjLZiQC/kh0HlyPyu9tKzM4iGPf7uG5sDEwWpYWvrh85RZYAYAIp7+XayNtqytXeLqWbjUUNcLC+fuG2mpLu7tPl5sZDAnpLk0mzFDir+BFJlkCECaKFuSBYSlA4pLWtiRjEygIyErFzyIKjreYTlbZKgaHrRlzoHotweXeAhEhIxPBTDBhQYgEYhNbybINhxY1sbSwwkbHOZrzs3VRmjmnOk6bOkrqxMHT9yCqyxNybAFMg1mWRBGYlg2eboOSFGdT+IwM3Eil6zBwXZF1xkSWkOa6qtHleceuQvC+g4pZXiaOt9jyDb24Q2qKC5XTSvrlK3ZHMW04nLdMPKtQOMzoGTzPz69YNP2vi7D11ftvQWYCzyt7jfwO10TQgL5hT6QAAAABJRU5ErkJggg==">
|
|
<script type="text/javascript">
|
|
function gId(e){return d.getElementById(e)}function cE(e){return d.createElement(e)}var d=document
|
|
</script> </head> <body> <body> <div class="top-part"> <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"><path
|
|
fill="#003fff" d="M6 22h8v4H6zM14 14h4v8h-4zM18 10h4v8h-4zM22 6h8v4h-8z"/></svg>
|
|
WLED Pixel Art Converter </h1> </div> <h2>
|
|
Convert image to WLED JSON (pixel art on WLED matrix)</h2> <p> <table
|
|
id="fieldTable" style="width:100%;table-layout:fixed;align-content:center"> <tr>
|
|
<td style="vertical-align:middle"> <label for="ledSetupSelector">Led setup:
|
|
</label> </td> <td class="adaptiveTD"> <select id="ledSetupSelector"
|
|
class="mainSelector"> <option value="matrix" selected="selected">2D Matrix
|
|
</option> <option value="r2l">Serpentine, first row right to left <-</option>
|
|
<option value="l2r">Serpentine, first row left to right -></option>
|
|
</select> </td> </tr> <tr> <td style="vertical-align:middle"> <label
|
|
for="formatSelector">Output format:</label> </td> <td class="adaptiveTD">
|
|
<select id="formatSelector" class="mainSelector"> <option value="wled"
|
|
selected="selected">WLED JSON</option> <option value="curl">CURL</option>
|
|
<option value="ha">Home Assistant YAML</option> </select> </td> </tr> <tr> <td
|
|
style="vertical-align:middle"> <label for="colorFormatSelector">
|
|
Color code format:</label> </td> <td class="adaptiveTD"> <select
|
|
id="colorFormatSelector" class="mainSelector"> <option value="hex"
|
|
selected="selected">HEX (#f4f4f4)</option> <option value="dec">DEC (244,244,244)
|
|
</option> </select> </td> </tr> <tr> <td style="vertical-align:middle"> <label
|
|
for="addressingSelector">Addressing:</label> </td> <td class="adaptiveTD">
|
|
<select id="addressingSelector" class="mainSelector"> <option value="hybrid"
|
|
selected="selected">Hybrid (#f0f0f0,10, 17, #f4f4f4)</option> <option
|
|
value="range">Range (10, 17, #f4f4f4)</option> <option value="single">
|
|
Single (#f4f4f4)</option> </select> </td> </tr> <tr> <td
|
|
style="vertical-align:middle"> <label for="brightnessNumber">Brightness:</label>
|
|
</td> <td style="vertical-align:middle;display:flex;align-items:center"> <input
|
|
type="range" id="brightnessNumber" min="1" max="255" value="128"> <span
|
|
id="brightnessValue">128</span> </td> </tr> <tr> <td
|
|
style="vertical-align:middle"> <label for="colorLimitNumber">
|
|
Max no of colors/JSON:</label> </td> <td
|
|
style="vertical-align:middle;display:flex;align-items:center"> <input
|
|
type="range" id="colorLimitNumber" min="1" max="512" value="256"> <span
|
|
id="colorLimitValue">256</span> </td> </tr> <tr class="ha-hide"> <td
|
|
style="vertical-align:middle"> <label for="haID">HA Device ID:</label> </td> <td
|
|
class="adaptiveTD"> <input class="fullTextField" type="text" id="haID"
|
|
value="pixel_art_controller_001"> </td> </tr> <tr class="ha-hide"> <td
|
|
style="vertical-align:middle"> <label for="haUID">HA Device Unique ID:</label>
|
|
</td> <td class="adaptiveTD"> <input class="fullTextField" type="text"
|
|
id="haUID" value="pixel_art_controller_001a"> </td> </tr> <tr class="ha-hide">
|
|
<td style="vertical-align:middle"> <label for="haName">HA Device Name:</label>
|
|
</td> <td class="adaptiveTD"> <input class="fullTextField" type="text"
|
|
id="haName" value="Pixel Art Kitchen"> </td> </tr> <tr> <td
|
|
style="vertical-align:middle"> <label for="curlUrl">Device IP/host name:</label>
|
|
</td> <td class="adaptiveTD"> <input class="fullTextField" type="text"
|
|
id="curlUrl" value> </td> </tr> <tr> <td style="vertical-align:middle"> <label
|
|
for="targetSegment">Target segment id:</label> </td> <td class="adaptiveTD">
|
|
<input class="flxTFld" type="number" id="segID" value="0" min="0" max="63">
|
|
<select id="targetSegment" class="adaptiveSelector"> </select> <div
|
|
id="getSegmentsDiv" class="segmentsDiv"></div> </td> </tr> </table> <table
|
|
class="scaleTableClass" id="scaleTable"
|
|
style="width:100%;table-layout:fixed;align-content:center"> <tr> <td
|
|
style="vertical-align:middle"> <div id="scaleDiv"> <svg
|
|
style="width:36px;height:36px" viewBox="0 0 24 24" onclick="switchScale()"
|
|
cursor="pointer"><path fill="currentColor"
|
|
d="M17 7H7a5 5 0 0 0-5 5 5 5 0 0 0 5 5h10a5 5 0 0 0 5-5 5 5 0 0 0-5-5M7 15a3 3 0 0 1-3-3 3 3 0 0 1 3-3 3 3 0 0 1 3 3 3 3 0 0 1-3 3z"/>
|
|
</svg> Scale image </div> </td> <td style="vertical-align:middle"> <div
|
|
id="sizeDiv" style="display:none"> <label for="sizeX">W : </label> <input
|
|
class="sizeInputFields" type="number" id="sizeX" min="1" value="16">
|
|
<label for="sizeY">H : </label> <input
|
|
class="sizeInputFields" type="number" id="sizeY" min="1" value="16"> </div>
|
|
</td> </tr> </table> </p> <p> <label for="file-picker"> <div id="drop-zone">
|
|
Drop image here <br>or <br> Click to select a file </div> </label> </p> <p>
|
|
<input type="file" id="file-picker" style="display:none"> </p><div
|
|
style="width:100%;text-align:center"> <img id="preview"
|
|
style="display:none;margin:0 auto" src="data:text/html;base64,"> </div> <div
|
|
id="raw-image-container" style="display:none"> <img id="image"
|
|
src="data:text/html;base64," alt="RawImage image"> </div> <p></p> <div
|
|
id="image-container" style="display:none"> <div id="image-info"
|
|
style="display:none"></div> <textarea id="JSONled" readonly="readonly">
|
|
</textarea> </div> <div id="button-container" style="display:none"> <button
|
|
id="copyJSONledbutton" class="buttonclass"></button> <div id="gap1" class="gap">
|
|
</div> <button id="sendJSONledbutton" class="buttonclass"></button> <div
|
|
id="gap2" class="gap"></div> <button id="fileJSONledbutton" class="buttonclass">
|
|
</button> </div> <div> <h3><div id="version">Version 1.0.6</div> - <a
|
|
href="https://github.com/werkstrom/WLED-PixelArtConverter/blob/main/README.md"
|
|
target="_blank">Help/About</a></h3> </div> </div> <div id="bottom-part"
|
|
style="display:none" class="bottom-part"></div> <canvas id="pixelCanvas">
|
|
</canvas> <script type="text/javascript">
|
|
var curlStart='curl -X POST "http://',curlMid1="/json/state\" -d '",curlEnd='\' -H "Content-Type: application/json"';const haStart="#Uncomment if you don't allready have these defined in your switch section of your configuration.yaml\n#- platform: command_line\n #switches:\n ",haMid1="\n friendly_name: ",haMid2="\n unique_id: ",haMid3="\n command_on: >\n ",haMid4='\n command_off: >\n curl -X POST "http://',haEnd='/json/state" -d \'{"on":false}\' -H "Content-Type: application/json"',haCommandLeading=" ",JSONledStringStart='{"on":true,"bri":',JSONledStringMid1=',"seg":{"id":',JSONledStringMid2=',"i":[',JSONledStringEnd="]}}";var accentColor="#eee",accentTextColor="#777",prsCol="#ccc",greenColor="#056b0a",redColor="#6b050c",scaleToggleOffd="M17,7H7A5,5 0 0,0 2,12A5,5 0 0,0 7,17H17A5,5 0 0,0 22,12A5,5 0 0,0 17,7M7,15A3,3 0 0,1 4,12A3,3 0 0,1 7,9A3,3 0 0,1 10,12A3,3 0 0,1 7,15Z",scaleToggleOnd="M17,7H7A5,5 0 0,0 2,12A5,5 0 0,0 7,17H17A5,5 0 0,0 22,12A5,5 0 0,0 17,7M17,15A3,3 0 0,1 14,12A3,3 0 0,1 17,9A3,3 0 0,1 20,12A3,3 0 0,1 17,15Z"
|
|
</script> <script type="text/javascript">
|
|
function getPixelRGBValues(e){httpArray=[],fileJSON=JSONledStringStart+gId("brightnessNumber").value+JSONledStringMid1+gId("targetSegment").value+JSONledStringMid2;const t=gId("targetSegment");let l=0;l="flex"==t.style.display?t.value:gId("segID").value;const a=gId("JSONled"),d=gId("colorLimitNumber").value;let i=!1,r=-1,n=gId("formatSelector");r=n.selectedIndex;const g=n.options[r].value;n=gId("ledSetupSelector"),r=n.selectedIndex;const o=n.options[r].value;n=gId("colorFormatSelector"),r=n.selectedIndex;let s=!0;"dec"==n.options[r].value&&(s=!1),n=gId("addressingSelector"),r=n.selectedIndex;let u=!0;"single"==n.options[r].value?u=!1:"hybrid"==n.options[r].value&&(i=!0);let h="",c="",S="'",I="'";s||(S="[",I="]");let v=!1,p="";var f=cE("canvas"),m=f.getContext("2d",{willReadFrequently:!0}),N=new Image;N.src=e,N.onload=function(){let e=gId("scaleDiv").children[0].children[0].getAttribute("fill"),t=gId("sizeX").value,r=gId("sizeY").value;(e!=accentColor||t<1||r<1)&&(t=N.width,r=N.height,(N.width>512||N.height>512)&&(t=16,r=16)),f.width=t,f.height=r,p="<p>Width: "+t+", Height: "+r+" (make sure this matches your led matrix setup)</p>",m.drawImage(N,0,0,t,r);var n=m.getImageData(0,0,t,r).data,y=[];let O=1;"l2r"==o&&(O=0);for(var J=0;J<n.length;J+=4){var b=n[J],M=n[J+1],x=n[J+2],w=n[J+3];let e=J/4,l=Math.floor(e/t),a=e;if("matrix"==o);else if((l+O)%2==0);else{a=l*t+(t-1-(a-l*t))}y.push([b,M,x,w,a,e,l])}y.sort((e,t)=>e[5]-t[5]);let E=[...y];E.sort((e,t)=>e[4]-t[4]);let R="",D=-1,A=E.length,T=0,k=[];for(let e=0;e<A;e++){let t=E[e],l=t[0],a=t[1],r=t[2],n=t[3],g="",o=-1;if(u)if(D<0&&(D=e),e<A-1){let t=E[e+1];t[0]==l&&t[1]==a&&t[2]==r||(o=e+1,g=D==e&&i?""==R?e+",":"":D+","+o+",")}else o=e+1,g=D+1==o&&i?""==R?e+",":"":D+","+o+",";else""==R&&(R=e),D=e,o=e;if(n<255&&(v=!0),o>-1){let t=l+","+a+","+r;if(s){const[e,d,i]=[l,a,r];t=""+[e,d,i].map(e=>e.toString(16).padStart(2,"0")).join("")}R=R+g+S+t+I,fileJSON=R+g+S+t+I,T+=1,T%d==0||e==A-1?(k.push(R),R=""):R+=",",D=-1}}R="";for(let e=0;e<k.length;e++){let t=JSONledStringStart+gId("brightnessNumber").value+JSONledStringMid1+l+JSONledStringMid2+k[e]+JSONledStringEnd;httpArray.push(t);let a=curlStart+gId("curlUrl").value+curlMid1+t+curlEnd;e>0&&(R+="\n",h+=" && "),R+=t,h+=a}c=haStart+gId("haID").value+haMid1+gId("haName").value+haMid2+gId("haUID").value+haMid3+h+haMid3+gId("curlUrl").value+haEnd,a.value="wled"==g?R:"curl"==g?h:"ha"==g?c:"ERROR!/n"+g+" is an unknown format.",fileJSON+=JSONledStringEnd;let U=gId("image-info"),z=gId("image-info");v&&(p+="<p><b>WARNING!</b> Transparency info detected in image. Transparency (alpha) has been ignored. To ensure you get the result you desire, use only solid colors in your image.</p>"),U.innerHTML=p,z.style.display="block",drawBoxes(y,t,r)}}
|
|
</script> <script type="text/javascript">
|
|
function drawBoxes(t,e,i){var l=gId("pixelCanvas"),n=l.getContext("2d",{willReadFrequently:!0});window.innerHeight<window.innerWidth?l.width=Math.floor(.98*window.innerHeight):l.width=Math.floor(.98*window.innerWidth);let d=Math.floor(l.width/e),h=(window.innerWidth-e*d)/2;l.height=d*i+10;for(let l=0;l<i;l++)for(let i=0;i<e;i++){let h=t[l*e+i],r="rgb("+h[0]+", "+h[1]+", "+h[2]+")",o=(h[0],h[1],h[2],h[4]),w="rgb(128,128,128)";n.fillStyle=r,n.fillRect(i*d,l*d,d,d),n.strokeStyle="#888888",n.lineWidth=1,n.strokeRect(i*d,l*d,d,d),n.font="10px Arial",n.fillStyle=w,n.textAlign="center",n.textBaseline="middle",n.fillText(o+1,i*d+d/2,l*d+d/2)}var r=n.getImageData(0,0,l.width,l.height);n.clearRect(0,0,l.width,l.height),l.width=window.innerWidth,n.putImageData(r,h,0)}
|
|
</script> <script type="text/javascript">
|
|
gId("curlUrl").value=location.host;let devMode=!1;const urlParams=new URLSearchParams(window.location.search);urlParams.has("dev")&&(devMode=!0),devMode?console.log("Developer mode active. Experimental and unstable functions active."):console.log('Developer mode inactive. Append "?dev" to the URL.'),devMode?(gId("fileJSONledbutton").style.display="buttonclass",gId("gap2").style.display="gap"):(gId("fileJSONledbutton").style.display="none",gId("gap2").style.display="none");let httpArray=[],fileJSON="";function gen(){if((gId("sizeX").value>0&&gId("sizeY").value>0||"none"==gId("sizeDiv").style.display)&&gId("curlUrl").value.length>0&&"none"!=gId("preview").style.display){let e=gId("preview").src;if(isValidBase64Gif(e))gId("image").src=e,getPixelRGBValues(e),gId("image-container").style.display="block",gId("button-container").style.display="";else{let t=gId("image-info"),n="<p><b>WARNING!</b> File does not appear to be a valid image</p>";t.innerHTML=n,t.style.display="block",gId("image-container").style.display="none",gId("JSONled").value="",devMode&&console.log("The string '"+e+"' is not a valid base64 image.")}}var e=gId("getSegmentsSVGpath");if(gId("curlUrl").value.length>0)e.setAttribute("fill",accentColor);else{e.setAttribute("fill",accentTextColor);let t=gId("targetSegment");t.style.display="none",t.innerHTML="",gId("segID").style.display="flex"}}async function postPixels(){(svg=gId("sendSvgP")).setAttribute("fill",prsCol);let e=!1;for(let t of httpArray)try{devMode&&console.log(t),devMode&&console.log(t.length);const e=await fetch("http://"+gId("curlUrl").value+"/json/state",{method:"POST",headers:{"Content-Type":"application/json"},body:t}),n=await e.json();devMode&&console.log(n)}catch(t){console.error(t),e=!0}e?(svg.setAttribute("fill",redColor),setTimeout((function(){svg.setAttribute("fill",accentTextColor)}),1e3)):(svg.setAttribute("fill",greenColor),setTimeout((function(){svg.setAttribute("fill",accentColor)}),1e3))}function sendAsFile(e,t,n){(svg=gId("fileSvgP")).setAttribute("fill",prsCol);var l=new Blob([e],{type:"application/json"});devMode&&(console.log(e),console.log(t),console.log(n));var i=new FormData;i.append("file",l,t);var o=new XMLHttpRequest;o.open("POST",n,!0),o.onload=()=>{200===o.status?(svg.setAttribute("fill",greenColor),setTimeout((function(){svg.setAttribute("fill",accentTextColor)}),1e3),devMode&&console.log("File uploaded successfully!")):(svg.setAttribute("fill",redColor),setTimeout((function(){svg.setAttribute("fill",accentColor)}),1e3),devMode&&console.log("File upload failed!"))},o.send(i)}gId("copyJSONledbutton").addEventListener("click",async()=>{let e=gId("JSONled");e.select();try{await navigator.clipboard.writeText(e.value)}catch(e){try{await d.execCommand("copy")}catch(e){console.error("Failed to copy text: ",e)}}}),gId("ledSetupSelector").addEventListener("change",()=>{gen()}),gId("sizeY").addEventListener("change",()=>{gen()}),gId("sizeX").addEventListener("change",()=>{gen()}),gId("formatSelector").addEventListener("change",()=>{gen()}),gId("colorFormatSelector").addEventListener("change",()=>{gen()}),gId("addressingSelector").addEventListener("change",()=>{gen()}),gId("brightnessNumber").addEventListener("change",()=>{gen()}),gId("colorLimitNumber").addEventListener("change",()=>{gen()}),gId("haID").addEventListener("change",()=>{gen()}),gId("haUID").addEventListener("change",()=>{gen()}),gId("haName").addEventListener("change",()=>{gen()}),gId("curlUrl").addEventListener("change",()=>{gen()}),gId("targetSegment").addEventListener("change",(function(){sop=this.options[this.selectedIndex],gId("sizeX").value=sop.dataset.x,gId("sizeY").value=sop.dataset.y,gen()})),gId("segID").addEventListener("change",()=>{gen()}),gId("preview").addEventListener("load",(function(){gen()})),gId("sendJSONledbutton").addEventListener("click",async()=>{"https:"===window.location.protocol?alert("Will only be available when served over http (or WLED is run over https)"):postPixels()}),gId("fileJSONledbutton").addEventListener("click",async()=>{if("https:"===window.location.protocol)alert("Will only be available when served over http (or WLED is run over https)");else{let e="TheName.json",t="http://"+gId("curlUrl").value+"/upload";sendAsFile(fileJSON,e,t)}});const dropZone=gId("drop-zone"),filePicker=gId("file-picker"),preview=gId("preview");function zoneClicked(e){e.preventDefault(),filePicker.click()}function dragEnter(e){e.preventDefault(),this.classList.add("drag-over")}function dragOver(e){e.preventDefault()}function dropped(e){e.preventDefault(),this.classList.remove("drag-over");updatePreview(e.dataTransfer.files[0])}function filePicked(e){updatePreview(e.target.files[0])}function updatePreview(e){const t=new FileReader;t.onload=()=>{preview.src=t.result,gId("preview").style.display=""},t.readAsDataURL(e)}function isValidBase64Gif(e){return!0}dropZone.addEventListener("dragenter",dragEnter),dropZone.addEventListener("dragover",dragOver),dropZone.addEventListener("drop",dropped),dropZone.addEventListener("click",zoneClicked),filePicker.addEventListener("change",filePicked),gId("brightnessNumber").oninput=()=>{let e=gId("brightnessNumber");gId("brightnessValue").textContent=e.value;let t=100*parseInt(e.value)/255;var n=`linear-gradient(90deg, #bbb ${t}%, #333 ${t}%)`;e.style.backgroundImage=n},gId("colorLimitNumber").oninput=()=>{let e=gId("colorLimitNumber");gId("colorLimitValue").textContent=e.value;let t=100*parseInt(e.value)/512;var n=`linear-gradient(90deg, #bbb ${t}%, #333 ${t}%)`;e.style.backgroundImage=n};for(var hideableRows=d.querySelectorAll(".ha-hide"),i=0;i<hideableRows.length;i++)hideableRows[i].classList.add("hide");function switchScale(){let e=gId("scaleDiv").children[0].children[0],t=e.getAttribute("fill"),n="";t===accentColor?(t=accentTextColor,n=scaleToggleOffd,gId("sizeDiv").style.display="none"):(t=accentColor,n=scaleToggleOnd,gId("sizeDiv").style.display=""),e.setAttribute("fill",t),e.setAttribute("d",n),gen()}function generateSegmentOptions(e){var t=gId("targetSegment");t.innerHTML="";for(var n=0;n<e.length;n++){var l=cE("option");l.value=e[n].value,l.text=e[n].text,l.dataset.x=e[n].x,l.dataset.y=e[n].y,t.appendChild(l),0===n&&(l.selected=!0)}}async function getSegments(){cv=gId("curlUrl").value;var e=gId("getSegmentsSVGpath");if(cv.length>0)try{var t=[];const l=await fetch("http://"+cv+"/json/state");let i=(await l.json()).seg.map(e=>({id:e.id,n:e.n,xs:e.start,xe:e.stop,ys:e.startY,ye:e.stopY}));for(var n=0;n<i.length;n++)t.push({value:i[n].id,text:i[n].n+" (index: "+i[n].id+")",x:i[n].xe-i[n].xs,y:i[n].ye-i[n].ys});generateSegmentOptions(t),gId("targetSegment").style.display="flex",gId("segID").style.display="none",e.setAttribute("fill",greenColor),setTimeout((function(){e.setAttribute("fill",accentColor)}),1e3)}catch(t){console.error(t),e.setAttribute("fill",redColor),setTimeout((function(){e.setAttribute("fill",accentColor)}),1e3),gId("targetSegment").style.display="none",gId("segID").style.display="flex"}else e.setAttribute("fill",redColor),setTimeout((function(){e.setAttribute("fill",accentTextColor)}),1e3),gId("targetSegment").style.display="none",gId("segID").style.display="flex"}function generateSegmentArray(e){for(var t=[],n=0;n<e;n++)t.push({value:n,text:"Segment index "+n});return t}gId("formatSelector").addEventListener("change",()=>{for(var e=0;e<hideableRows.length;e++)hideableRows[e].classList.toggle("hide","ha"!==gId("formatSelector").value)});var segmentData=generateSegmentArray(10);generateSegmentOptions(segmentData),gId("getSegmentsDiv").innerHTML='<svg id=getSegmentsSVG style="width:36px;height:36px;cursor:pointer" viewBox="0 0 24 24" onclick="getSegments()"><path id=getSegmentsSVGpath fill="currentColor" d="M6.5 20Q4.22 20 2.61 18.43 1 16.85 1 14.58 1 12.63 2.17 11.1 3.35 9.57 5.25 9.15 5.68 7.35 7.38 5.73 9.07 4.1 11 4.1 11.83 4.1 12.41 4.69 13 5.28 13 6.1V12.15L14.6 10.6L16 12L12 16L8 12L9.4 10.6L11 12.15V6.1Q9.1 6.45 8.05 7.94 7 9.43 7 11H6.5Q5.05 11 4.03 12.03 3 13.05 3 14.5 3 15.95 4.03 17 5.05 18 6.5 18H18.5Q19.55 18 20.27 17.27 21 16.55 21 15.5 21 14.45 20.27 13.73 19.55 13 18.5 13H17V11Q17 9.8 16.45 8.76 15.9 7.73 15 7V4.68Q16.85 5.55 17.93 7.26 19 9 19 11 20.73 11.2 21.86 12.5 23 13.78 23 15.5 23 17.38 21.69 18.69 20.38 20 18.5 20M12 11.05Z" /></svg>',gId("fileJSONledbutton").innerHTML='<svg style="width:36px;height:36px" viewBox="0 0 24 24"><path id=fileSvgP fill="currentColor" d="M20 18H4V8H20M20 6H12L10 4H4A2 2 0 0 0 2 6V18A2 2 0 0 0 4 20H20A2 2 0 0 0 22 18V8A2 2 0 0 0 20 6M16 17H14V13H11L15 9L19 13H16Z" /></svg> File to device',gId("copyJSONledbutton").innerHTML='<svg class="svg-icon" style="width:36px;height:36px" viewBox="0 0 24 24"> <path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z" /> </svg> Copy to clipboard',gId("sendJSONledbutton").innerHTML='<svg class="svg-icon" style="width:36px;height:36px" viewBox="0 0 24 24"> <path id=sendSvgP fill="currentColor" d="M6.5 20Q4.22 20 2.61 18.43 1 16.85 1 14.58 1 12.63 2.17 11.1 3.35 9.57 5.25 9.15 5.88 6.85 7.75 5.43 9.63 4 12 4 14.93 4 16.96 6.04 19 8.07 19 11 20.73 11.2 21.86 12.5 23 13.78 23 15.5 23 17.38 21.69 18.69 20.38 20 18.5 20H13Q12.18 20 11.59 19.41 11 18.83 11 18V12.85L9.4 14.4L8 13L12 9L16 13L14.6 14.4L13 12.85V18H18.5Q19.55 18 20.27 17.27 21 16.55 21 15.5 21 14.45 20.27 13.73 19.55 13 18.5 13H17V11Q17 8.93 15.54 7.46 14.08 6 12 6 9.93 6 8.46 7.46 7 8.93 7 11H6.5Q5.05 11 4.03 12.03 3 13.05 3 14.5 3 15.95 4.03 17 5.05 18 6.5 18H9V20M12 13Z" /> </svg> Send to device';var svg=gId("getSegmentsSVGpath");gId("curlUrl").value.length>0&&svg.setAttribute("fill",accentColor)
|
|
</script> </body> </body></html>
|