Repository: werkstrom/WLED-PixelArtConverter Branch: main Commit: 755377286fbe Files: 21 Total size: 195.5 KB Directory structure: gitextract_fy85wnci/ ├── .github/ │ └── workflows/ │ ├── env.yml │ └── manual.yml ├── LICENSE ├── README.md ├── RELEASENOTES.md ├── archived/ │ ├── pixart.htm │ └── pixartmin.htm ├── beta/ │ ├── pixart.htm │ └── releasenotes.md ├── examples/ │ └── filename ├── html/ │ ├── boxdraw.js │ ├── getPixelValues.js │ ├── index.html │ ├── index.js │ ├── pixartmin.html │ ├── site.webmanifest │ ├── statics.js │ └── styles.css ├── infoFiles/ │ ├── FlowDesignDocument.md │ └── runnerFlowTemplate.json └── pixart.htm ================================================ FILE CONTENTS ================================================ ================================================ FILE: .github/workflows/env.yml ================================================ version_string: "Version ${{ inputs.version }}" ================================================ FILE: .github/workflows/manual.yml ================================================ # This is a basic workflow that is manually triggered name: Manual workflow # Controls when the action will run. Workflow runs when manually triggered using the UI # or API. on: workflow_dispatch: # Inputs the workflow accepts. inputs: version: # Friendly description to be shown in the UI instead of 'name' description: 'Version (YY.M.X)' # Default value if no value is explicitly provided default: '99.1.1' # Input has to be provided for the workflow to run required: true # A workflow run is made up of one or more jobs that can run sequentially or in parallel jobs: # This workflow contains a single job called "greet" greet: # The type of runner that the job will run on runs-on: ubuntu-latest # Steps represent a sequence of tasks that will be executed as part of the job steps: # Runs a single command using the runners shell - name: Checkout uses: actions/checkout@v3.3.0 with: ref: main - name: Pull the latest changes run: git pull - name: Check if the file is present run: ls - name: Check if the file is present run: ls html/ - name: Copy and Rename File run: cp html/index.html pixartmin.htm - name: Check if the file is present run: ls - name: Check if the file is present run: ls html/ - name: Add the changes run: git add pixartmin.htm - name: Use env file env: envFile: manualenv.yml run: | echo "The version is ${{ manualenv.version_string }}" - name: Commit the changes run: git -c user.name=${{ secrets.NAME }} -c user.email=${{ secrets.EMAIL }} commit -m ${{ manualenv.version_string }} - name: Push the changes run: git push #run: git push git@github.com:myname/myproject.git ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2023 Henrik Werkström Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ # Download instructions For stable (1.0.8) ***Right***-Click [here](https://raw.githubusercontent.com/werkstrom/WLED-PixelArtConverter/main/pixart.htm) and select save to your local computer. For beta (1.1.0) ***Right***-Click [here](https://raw.githubusercontent.com/werkstrom/WLED-PixelArtConverter/main/beta/pixart.htm) and select save to your local computer. Acctual text may differ depending on browser, but for Chrome (as of writing) the menu item would to select be *[Save link as...]*. # Additional instructions There are now instructions directly in the WLED documentation [here](https://kno.wled.ge/features/pixel-art-converter/). As the Pixel Art Converter project migrates to main WLED project, documentation will most likely primarily be done there as it is beneficial to have a complete, end-to-end documentation on how to set up WLED and use Pixel Art Converter together. # WLED-PixelArtConverter Convert any image your browser can render into pixel art for WLED This is a tool for making it easy to show pixel art on a LED panel run by WLED Find out more about the awesome [WLED software](https://kno.wled.ge/) or their [GitHub](https://github.com/Aircoookie/WLED) * Please read "Current notes" at the end of the document for known issues and important hints.* * *To run* ***directly*** *from WLED device use pixartmin.html according to* ***instructions below.*** * As the PixelArtConverter has moved into the main WLED project, sourcecode will no longer be available here. Only downloadable stand alones and documentation. * With the official WLED V0.14.0-b1 there are some issues with the 2D matrix implementation. It's the first release, so no surprise. Many (all known) are fixed and available in the nightly builds. You can get one here but be aware it is development builds. [https://wled-install.github.io/](https://wled-install.github.io/) ## Most notable functions - You can convert almost any image (tested with at least PNG, JPG, WEBP, GIF) - You can upload the generated settings directly to your WLED device, with a click of a button - If you want to trigger your image from Home Assistant the tool also generates the entire YAML for your configuration.yaml - If you want to trigger your image from any other place/system the tool generates a complete CURL command - You can adjust the format you send the data to WLED in(to fit your specific setup, i.e. slow or limited devices) - Generates several types led orders, to fit your setup (though with 2D setup you should not need to anymore) - Very small footprint. Only about 35 kB excluding favicons - 100% pure Javascript/html/CSS - Runs in your browser only, no sending iimages to any cloud services - Communicates with your device(s) to get valid options. ## Basic Operations 1. First download the pixart.htm file and save it to some where on your computer. Any OS should do really since its purely run inside the browser. *Note: As of V 1.0.8 only the minified version is distributed as it has all the functionality, but in a smaller package.* 2. And open the pixart.htm file in any modern browser. 3. Select the settings according to your settup and what you want to do. 4. Select an image (or drag and drop one) and make sure the preview is visable (the very small image). This indicates your image can be read by the tool 5. Click the button below to convert your image. 6. You should be able to se a large preview of the generated led data at the bottom of the page **A. Direct upload** 7. Press the button to send your image to your WLED device. 8. Validate the image reached the device and is looking as expected. If not change the parameters in PixelArtConverer and try again. 9. Create a preset on your device from the current setting (follow the instructions [here](https://kno.wled.ge/features/presets/) TL;DR: Press the "Create Preset" button. 10. If you want to upload the same image to another device, simply change the Device IP/host name and click "Send to device" again **B. Use elsewhere** 7. Copy the generated code if you want to use it outside of the PixelArtConverter/WLED Note: Since you are running the tool localy, you will not be allowed to copy to your clipboard automatically. You will ned to mark the entire text (ctrl+a) and copy it (ctrl+c). 8. Paste the text into your tool of choice. **Note: The Preset API setup (where you can paste JSON and create a preset) does currently not support multiple commands, i.e. your entire settings JSON *must* be in one single command string.** ## Running directly on your WLED device *As PixelArtConverter is no merged into the main WLED project. This option will shortly be available as default* Most WLED devices are low power very limited compute so it is important to make life as easy as possible for it. That's why there is a one-file-solution for you to use if you want to make PixelArtConverter available by accessing your WLED device. Follow these steps: 1. Download the *pixart.htm* file 2. Direct you browser to http://[your.device.ip]/edit 3. Upload the *pixart.htm* file using the UI 4. Direct you browser to http://[your.device.ip]/pixart.htm And you should be good to go. ## Notes and tips ### Image Size You can resize your images to fit your led setup. The image is projected exactly as it is, onto exactly the size you provide. That means that if your source file aspect ratio does not fit your target size aspect ratio, your image will get destorted. Still in many cases it is not noticable. ### Output format Pretty self explainatory. If you are to upload to your device from PixelArtConverter you should select WLED JSON ### Color code format Though WLED can handle both. The documentation explicitly states HEX is faster and requires less resources. Use it whenever you can. ### Addressing PixelArtConverter can either generate one color code per led/pixel, Or, it can identify ranges within your image. Many times the ranges option generates fewer commands and is thus faster and more reliable. But not allways. If you upload to your device and saves it as a preset, it doesn't matter. The preset is based on WLED's internal format and is thus optimized. But if you are to trigger the image from another place, like Home Assistant it can make a lot of difference, depending on your image. The Ukranian flag (that everybody knows by now) is MUCH faster and easier in range mode, but a chess board migt actually be slower... As of version 1.0.1 there is a hybrid mode that utilizes the ability to mix single and range. this should be the default for anyone to use from now on. ### Number of colors per command WLED is running on very limited devices, and you're throwing a massive amount af data on them in a very short time. To make things easy on the devices, limit your number of colors. You can test with your device how much it can handle. But this will vary. ## Target segment id If multiple segements are set up in WLED you can send it to any one of them. The most convenient way to set a valid target is to query the device for valid IDs. Simply make sure your device's IP/host is set in the field above and click the "Get from cloud" icon. If connection is successful, the icon briefly turns green and you get a selection of available segment IDs to select from. If connection is unsuccesfull the icon turs red briefly in which case you can still manually set a segment and generate code for later use. To reset the selection change the IP/host and click the button again. ### Home Assistant The code generated will create a switch for you within home Assistant. What you do with it, how you trigger it, how you make it look in Home Assistant... Anything you wonder about that. Head over to the [Home Assistant Forum](https://community.home-assistant.io/) ### Where to find images If you want to create your own or modify/edit then [www.pixilart.com](https://www.pixilart.com) is an excelent tool If you want to find old sprites from old games try out [www.spriters-resource.com](https://www.spriters-resource.com) or [opengameart.org](https://opengameart.org/) There are also some (a few) here in the folder "examples" ## Current notes ### http, https and the issue with **mixed content** in web browsers As a security meassure web browser do not allow you to access resources (web panges and web services) through http (un encrypted) from a page (like PixelArtConverter) when it is loaded through https (encrypted). Also public webservers (like [ledcalculator.werkstrom.com](https://ledcalculator.werkstrom.com)) "must" (in practise) use https. This means two things. 1. In order to upload directly to your device, PixelArtConverter **must** be loaded in the same security context (http/https) as WLED. Since most WLED devices are local IoT devices it's mainly http. That's why you need to download the files and run them locally. A more convenient sollution is to have WLED serve you the page directly as that will solve any issues with possible missmatch. As of today you can set this up manually by uploading the files to your device @ [your.device.ip]/edit and then loading it to your browser using [your.device.ip]/index.html. We're looking into adding it in a more convenient way. 2. You cannot use the tool @ [ledcalculator.werkstrom.com](https://ledcalculator.werkstrom.com) to upload **directly** to your device. The generated JSON, CURL and Home Assistant code will work just fine though. ### Possible issue with single addressing after WLED V0.14.0-b1 As of V0.14.0-b1 there is a bug in WLED that PixelArtConverter have a workaround for that will probably break your upload if you 1. Use **Single** addressing (and you shouldn't) 2. Have a later build of WLED. It should in practise not be a problem, but keep in mind if you get issues ================================================ FILE: RELEASENOTES.md ================================================ # Version 1.0.6 ## Main take aways - Streamlined the conversion process - Image generates as soon as there is enough input to generete an image - Image regenerates on value changes. No need to press convert button - Segments are now named as on the device - If are selected, and rescale is active, w/h will be automatically set from the selected segment - Buttons that communicate with the device is more informative of success (green) or fail (red) - Convertbutton removed (since there is no use for pressing it any more) - Minor bugfixes and adjustments # Version 1.0.5 ## Main take aways - Querying the device for available segments - Manually input any segment id (0-63) - Preview matrix is now centered also on landscape displays - Several UI adjustments - Alignment with WLED profile - Development moved to main WLED project - Changed file ending to htm to align with WLED naming # Version 1.0.4 ## Main take aways - Minor visual adjustments # Version 1.0.3 ## Main take aways - Possible to send your image to different segments. There appear to be some sort of issue we havent identified, so currently only segment 0 works. Bur we need to get the function in there to test, so... Test on! - Minor adjustments and bugfixes # Version 1.0.2 ## Main take aways - Developer mode: Some new and experimental features will be turned off unless you run in developer mode. To enter developermode append "?dev" to the url. Example: http://192.168.0.123/pixartmin.htm?dev - File to device: Experimental feature to send the generated code as a file to the device instead of using the JSON API. Will not do anything more on the device at the moment. - Minor adjustmensts ================================================ FILE: archived/pixart.htm ================================================
| 128 | |
| 256 | |
| Scale image |
| 128 | |
| 256 | |
| Scale image |
| 128 | |
| 256 | |
| Scale image |
| Generate flow file |
|
Width: ' + sizeX + ', Height: ' + sizeY + ' (make sure this matches your led matrix setup)
' // Draw the image onto the canvas context.drawImage(image, 0, 0, sizeX, sizeY); // Get the pixel data from the canvas var pixelData = context.getImageData(0, 0, sizeX, sizeY).data; // Create an array to hold the RGB values of each pixel var pixelRGBValues = []; // If the first row of the led matrix is right -> left let right2leftAdjust = 1; if (ledSetupSelection == 'l2r'){ right2leftAdjust = 0; } // Loop through the pixel data and get the RGB values of each pixel for (var i = 0; i < pixelData.length; i += 4) { var r = pixelData[i]; var g = pixelData[i + 1]; var b = pixelData[i + 2]; var a = pixelData[i + 3]; let pixel = i/4 let row = Math.floor(pixel/sizeX); let led = pixel; if (ledSetupSelection == 'matrix'){ //Do nothing, the matrix is set upp like the index in the image //Every row starts from the left, i.e. no zigzagging } else if ((row + right2leftAdjust) % 2 === 0) { //Setup is traditional zigzag //right2leftAdjust basically flips the row order if = 1 //Row is left to right //Leave led index as pixel index } else { //Setup is traditional zigzag //Row is right to left //Invert index of row for led let indexOnRow = led - (row * sizeX); let maxIndexOnRow = sizeX - 1; let reversedIndexOnRow = maxIndexOnRow - indexOnRow; led = (row * sizeX) + reversedIndexOnRow; } // Add the RGB values to the pixel RGB values array pixelRGBValues.push([r, g, b, a, led, pixel, row]); } pixelRGBValues.sort((a, b) => a[5] - b[5]); //Copy the values to a new array for resorting let ledRGBValues = [... pixelRGBValues]; //Sort the array based on led index ledRGBValues.sort((a, b) => a[4] - b[4]); //Generate JSON in WLED format let JSONledString = ''; let JSONledStringShort = ''; //Set starting values for the segment check to something that is no color let segmentStart = -1; let maxi = ledRGBValues.length; let curentColorIndex = 0 let commandArray = []; //For evry pixel in the LED array for (let i = 0; i < maxi; i++) { let pixel = ledRGBValues[i]; let r = pixel[0]; let g = pixel[1]; let b = pixel[2]; let a = pixel[3]; let segmentString = ''; let segmentEnd = -1; if(segmentValueCheck){ if (segmentStart < 0){ //This is the first led of a new segment segmentStart = i; } //Else we allready have a start index if (i < maxi - 1){ let iNext = i + 1; let nextPixel = ledRGBValues[iNext]; if (nextPixel[0] != r || nextPixel[1] != g || nextPixel[2] != b ){ //Next pixel has new color //The current segment ends with this pixel segmentEnd = i + 1 //WLED wants the NEXT LED as the stop led... if (segmentStart == i && hybridAddressing){ //If only one led/pixel, no segment info needed if (JSONledString == ''){ //If addressing is single, we need to start every command with a starting possition segmentString = '' + i + ','; //Fixed to b2 } else{ segmentString = '' } } else { segmentString = segmentStart + ',' + segmentEnd + ','; } } } else { //This is the last pixel, so the segment must end segmentEnd = i + 1; if (segmentStart + 1 == segmentEnd && hybridAddressing){ //If only one led/pixel, no segment info needed if (JSONledString == ''){ //If addressing is single, we need to start every command with a starting possition segmentString = '' + i + ','; //Fixed to b2 } else{ segmentString = '' } } else { segmentString = segmentStart + ',' + segmentEnd + ','; } } } else{ //Write every pixel if (JSONledString == ''){ //If addressing is single, we need to start every command with a starting possition JSONledString = i //Fixed to b2 } segmentStart = i segmentEnd = i //Segment string should be empty for when addressing single. So no need to set it again. } if (a < 255){ hasTransparency = true; //If ANY pixel has alpha < 255 then this is set to true to warn the user } if (segmentEnd > -1){ //This is the last pixel in the segment, write to the JSONledString //Return color value in selected format let colorValueString = r + ',' + g + ',' + b ; if (hexValueCheck){ const [red, green, blue] = [r, g, b]; colorValueString = `${[red, green, blue].map(x => x.toString(16).padStart(2, '0')).join('')}`; } else{ //do nothing, allready set } // Check if start and end is the same, in which case remove JSONledString = JSONledString + segmentString + colorSeparatorStart + colorValueString + colorSeparatorEnd; fileJSON = JSONledString + segmentString + colorSeparatorStart + colorValueString + colorSeparatorEnd; curentColorIndex = curentColorIndex + 1; // We've just added a new color to the string so up the count with one if (curentColorIndex % maxNoOfColorsInCommandSting === 0 || i == maxi - 1) { //If we have accumulated the max number of colors to send in a single command or if this is the last pixel, we should write the current colorstring to the array commandArray.push(JSONledString); JSONledString = ''; //Start on an new command string } else { //Add a comma to continue the command string JSONledString = JSONledString + ',' } //Reset segment values segmentStart = - 1; } } JSONledString = '' //For evry commandString in the array for (let i = 0; i < commandArray.length; i++) { let thisJSONledString = JSONledStringStart + document.getElementById('brightnessNumber').value + JSONledStringMid1 + document.getElementById('targetSegment').value + JSONledStringMid2 + commandArray[i] + JSONledStringEnd; httpArray.push(thisJSONledString); let thiscurlString = curlStart + document.getElementById('curlUrl').value + curlMid1 + thisJSONledString + curlEnd; //Aggregated Strings That should be returned to the user if (i > 0){ JSONledString = JSONledString + '\n'; curlString = curlString + ' && '; } JSONledString = JSONledString + thisJSONledString; curlString = curlString + thiscurlString; } haString = haStart + document.getElementById('haID').value + haMid1 + document.getElementById('haName').value + haMid2 + document.getElementById('haUID').value + haMid3 +curlString + haMid3 + document.getElementById('curlUrl').value + haEnd; if (formatSelection == 'wled'){ JSONled.value = JSONledString; } else if (formatSelection == 'curl'){ JSONled.value = curlString; } else if (formatSelection == 'ha'){ JSONled.value = haString; } else { JSONled.value = 'ERROR!/n' + formatSelection + ' is an unknown format.' } fileJSON = fileJSON + JSONledStringEnd; let infoDiv = document.getElementById('image-info'); let canvasDiv = document.getElementById('image-info'); if (hasTransparency){ imageInfo = imageInfo + 'WARNING! 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.
' } infoDiv.innerHTML = imageInfo; canvasDiv.style.display = "block" //Drawing the image drawBoxes(pixelRGBValues, sizeX, sizeY); } } ================================================ FILE: html/index.html ================================================
| 255 | |
| 256 | |
|
|
WARNING! File does not appear to be a valid image
' infoDiv.innerHTML = imageInfo; infoDiv.style.display = "block" document.getElementById('image-container').style.display = "none"; document.getElementById('JSONled').value = ''; console.log("The string '" + base64Image + "' is not a valid base64 image."); } }); // Code for copying the generated string to clipboard copyJSONledbutton.addEventListener('click', async () => { let JSONled = document.getElementById('JSONled'); JSONled.select(); try { await navigator.clipboard.writeText(JSONled.value); } catch (err) { try { await document.execCommand("copy"); } catch (err) { console.error('Failed to copy text: ', err); } } }); sendJSONledbutton.addEventListener('click', async () => { if (window.location.protocol === "https:") { alert('Will only be available when served over http (or WLED is run over https)'); } else { postPixels(); } }); fileJSONledbutton.addEventListener('click', async () => { if (window.location.protocol === "https:") { alert('Will only be available when served over http (or WLED is run over https)'); } else { let JSONFileName = 'TheName.json' let urlString = 'http://'+document.getElementById('curlUrl').value+'/upload' sendAsFile(fileJSON, JSONFileName, urlString); } }); async function postPixels() { for (let i of httpArray) { try { console.log(i); console.log(i.length); const response = await fetch('http://'+document.getElementById('curlUrl').value+'/json/state', { method: 'POST', headers: { 'Content-Type': 'application/json' //'Content-Type': 'text/html; charset=UTF-8' }, body: i }); const data = await response.json(); console.log(data); } catch (error) { console.error(error); } } } //File uploader code const dropZone = document.getElementById('drop-zone'); const filePicker = document.getElementById('file-picker'); const preview = document.getElementById('preview'); // Listen for dragenter, dragover, and drop events dropZone.addEventListener('dragenter', dragEnter); dropZone.addEventListener('dragover', dragOver); dropZone.addEventListener('drop', dropped); dropZone.addEventListener('click', zoneClicked); // Listen for change event on file picker filePicker.addEventListener('change', filePicked); // Handle zone click function zoneClicked(e) { e.preventDefault(); //this.classList.add('drag-over'); //alert('Hej'); filePicker.click(); } // Handle dragenter function dragEnter(e) { e.preventDefault(); this.classList.add('drag-over'); } // Handle dragover function dragOver(e) { e.preventDefault(); } // Handle drop function dropped(e) { e.preventDefault(); this.classList.remove('drag-over'); // Get the dropped file const file = e.dataTransfer.files[0]; updatePreview(file); } // Handle file picked function filePicked(e) { // Get the picked file const file = e.target.files[0]; updatePreview(file); } // Update the preview image function updatePreview(file) { // Use FileReader to read the file const reader = new FileReader(); reader.onload = function() { // Update the preview image preview.src = reader.result; document.getElementById("submitConvertDiv").style.display = ""; }; reader.readAsDataURL(file); } function isValidBase64Gif(string) { // Use a regular expression to check that the string is a valid base64 string /* const base64gifPattern = /^data:image\/gif;base64,([A-Za-z0-9+/:]{4})*([A-Za-z0-9+/:]{3}=|[A-Za-z0-9+/:]{2}==)?$/; const base64pngPattern = /^data:image\/png;base64,([A-Za-z0-9+/:]{4})*([A-Za-z0-9+/:]{3}=|[A-Za-z0-9+/:]{2}==)?$/; const base64jpgPattern = /^data:image\/jpg;base64,([A-Za-z0-9+/:]{4})*([A-Za-z0-9+/:]{3}=|[A-Za-z0-9+/:]{2}==)?$/; const base64webpPattern = /^data:image\/webp;base64,([A-Za-z0-9+/:]{4})*([A-Za-z0-9+/:]{3}=|[A-Za-z0-9+/:]{2}==)?$/; */ //REMOVED, Any image appear to work as long as it can be drawn to the canvas. Leaving code in for future use, possibly if (1==1 || base64gifPattern.test(string) || base64pngPattern.test(string) || base64jpgPattern.test(string) || base64webpPattern.test(string)) { return true; } else { //Not OK return false; } } document.getElementById("brightnessNumber").oninput = function() { document.getElementById("brightnessValue").textContent = this.value; } document.getElementById("colorLimitNumber").oninput = function() { document.getElementById("colorLimitValue").textContent = this.value; } var formatSelector = document.getElementById("formatSelector"); var hideableRows = document.querySelectorAll(".ha-hide"); for (var i = 0; i < hideableRows.length; i++) { hideableRows[i].classList.add("hide"); } formatSelector.addEventListener("change", function() { for (var i = 0; i < hideableRows.length; i++) { hideableRows[i].classList.toggle("hide", this.value !== "ha"); } }); function switchScale() { let scalePath = document.getElementById("scalePath"); let scaleTogglePath = document.getElementById("scaleTogglePath"); let color = scalePath.getAttribute("fill"); let d = '' if (color === accentColor) { color = accentTextColor; d = scaleToggleOffd document.getElementById("sizeDiv").style.display = "none"; // Set values to actual XY of image, if possible } else { color = accentColor; d = scaleToggleOnd document.getElementById("sizeDiv").style.display = ""; } scalePath.setAttribute("fill", color); scaleTogglePath.setAttribute("fill", color); scaleTogglePath.setAttribute("d", d); } function sendAsFile(jsonStringInput, fileName, urlString) { //var jsonString = JSON.stringify({name: "value"}); var file = new Blob([jsonStringInput], {type: 'application/json'}); console.log(jsonStringInput) console.log(fileName); console.log(urlString); var formData = new FormData(); formData.append('file', file, fileName); var xhr = new XMLHttpRequest(); xhr.open('POST', urlString, true); xhr.onload = function() { if (xhr.status === 200) { console.log('File uploaded successfully!'); } else { console.log('File upload failed!'); } }; xhr.send(formData); } function generateSegmentOptions(array) { //This function is prepared for a name property on each segment for easier selection //Currently the name is generated generically based on index var select = document.getElementById("targetSegment"); select.innerHTML = ""; for (var i = 0; i < array.length; i++) { var option = document.createElement("option"); option.value = array[i].value; option.text = array[i].text; select.appendChild(option); if(i === 0) { option.selected = true; } } } //Initial population of segment selection function generateSegmentArray(noOfSegments) { var arr = []; for (var i = 0; i < noOfSegments; i++) { arr.push({ value: i, text: "Segment index " + i }); } return arr; } //Animate matrix var matrixcircles = document.querySelectorAll("#logomatrix path"); var intervalId; // Function that changes the color of a random circle to a lighter purple function changeColorOfDot() { // Get a random number between 0 and the number of circles var randomIndex = Math.floor(Math.random() * matrixcircles.length); // Get the circle at the random index var randomCircle = matrixcircles[randomIndex]; // Store the current fill color var currentColor = randomCircle.getAttribute("fill"); // Change the color of the circle randomCircle.setAttribute("fill", "#bb8fbc"); setTimeout(() => { randomCircle.setAttribute("fill", currentColor); clearInterval(intervalId); intervalId = setInterval(changeColorOfDot, randomInterval()); }, 500); } function randomInterval() { var interval = Math.floor(Math.random() * (5 - 1 + 1)) + 1; return interval * 1000; } // call the function changeColorOfDot every 10 seconds intervalId = setInterval(changeColorOfDot, randomInterval()); var segmentData = generateSegmentArray(10); generateSegmentOptions(segmentData); document.getElementById("fileJSONledbutton").innerHTML = ' File to device' document.getElementById("convertbutton").innerHTML = ' Convert to WLED JSON '; document.getElementById("copyJSONledbutton").innerHTML = ' Copy to clipboard'; document.getElementById("sendJSONledbutton").innerHTML = ' Send to device'; ================================================ FILE: html/pixartmin.html ================================================
| 255 | |
| 256 | |
|
|
| 128 | |
| 256 | |
| Scale image |