Skip to content

Commit

Permalink
Rearranged the sections, moved from accordion expanders to tabs.
Browse files Browse the repository at this point in the history
Added image map input tab.
Replaced Twitter link with Mastodon.
Fixed copy to clipboard success messages.
Moved default input maps from html to code.
  • Loading branch information
jasoncoon committed Oct 2, 2023
1 parent 67561b6 commit 47e5de2
Show file tree
Hide file tree
Showing 7 changed files with 703 additions and 511 deletions.
845 changes: 364 additions & 481 deletions index.htm

Large diffs are not rendered by default.

165 changes: 145 additions & 20 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,29 @@
import { getColorAtBrightness } from "./js/color.js";
import { parseCoordinatesText } from "./js/coordinates.js";
import { beat8, beatsin8, CHSV, cos8, CRGB, generateFastLedMapCode, sin8 } from "./js/fastled.js";
import { parseLayoutText } from "./js/layout.js";
import { defaultCoordinates, parseCoordinatesText } from "./js/coordinates.js";
import { CHSV, CRGB, beat8, beatsin8, cos8, generateFastLedMapCode, sin8 } from "./js/fastled.js";
import { drawImageMap, getCursorPosition } from "./js/image.js";
import { defaultLayout, parseLayoutText } from "./js/layout.js";
import { mapNumber } from "./js/math.js";
import { palettes } from "./js/palettes.js";
import { getPatternCode } from "./js/patterns.js";
import { parsePixelblazeText } from "./js/pixelblaze.js";
import { defaultPixelblazeMap, parsePixelblazeText } from "./js/pixelblaze.js";

let imageInput;
let imageScaleFactor = 1;
const devicePixelRatio = window.devicePixelRatio || 1;

// get some elements by id
const buttonPlayPause = document.getElementById("buttonPlayPause");

const canvasPreview = document.getElementById("canvasPreview");
const canvasImageInput = document.getElementById("canvasImageInput");
const canvasSelectedPalette = document.getElementById("canvasSelectedPalette");

const codeFastLED = document.getElementById("codeFastLED");
const codePixelblaze = document.getElementById("codePixelblaze");

const context = canvasPreview.getContext("2d");
const contextImageInput = canvasImageInput.getContext("2d");
const contextSelectedPalette = canvasSelectedPalette.getContext("2d");

const inputCenterX = document.getElementById("inputCenterX");
Expand All @@ -26,6 +33,7 @@ const inputWidth = document.getElementById("inputWidth");
const inputPreviewCode = document.getElementById("inputPreviewCode");
const inputPreviewFontSize = document.getElementById("inputPreviewFontSize");
const inputPreviewSpeed = document.getElementById("inputPreviewSpeed");
const inputImage = document.getElementById("inputImage");

const selectPalette = document.getElementById("selectPalette");
const selectPreviewText = document.getElementById("selectPreviewText");
Expand Down Expand Up @@ -65,7 +73,7 @@ function onCopyCodeClick() {

function onCopyCoordinatesClick() {
copyElementValueToClipboard(textAreaCoordinates);
const div = document.getElementById("divCopyCoordinates");
const div = document.getElementById("divCopyCoordinatesInput");
div.innerText = "Copied to clipboard";
div.className = "visible input-group-text";

Expand All @@ -74,7 +82,7 @@ function onCopyCoordinatesClick() {

function onCopyLayoutClick() {
copyElementValueToClipboard(textAreaLayout);
const div = document.getElementById("divCopyLayout");
const div = document.getElementById("divCopyLayoutInput");
div.innerText = "Copied to clipboard";
div.className = "visible input-group-text";

Expand Down Expand Up @@ -109,6 +117,104 @@ function onGenerateCode() {
generateCode();
}

function onCanvasImageInputKeyDown(event) {
console.log(event);
}

function onImageInputChange(event) {
const files = [...event.target.files];
console.log({files});
const file = files.find(f => /image/.test(f.type));
if (!file) {
alert('Invalid file');
return;
}
const url = window.URL || window.webkitURL;
const objectUrl = url.createObjectURL(file);

contextImageInput.clearRect(0, 0, canvasImageInput.width, canvasImageInput.height);
imageInput = new Image();

imageInput.onload = () => {
contextImageInput.imageSmoothingEnabled = imageInput.width > 255 || imageInput.height > 255;

let canvasWidth = canvasImageInput.width;
let canvasHeight = canvasImageInput.height;

console.log({canvasWidth, canvasHeight});

const imageWidth = imageInput.width;
const imageHeight = imageInput.height;

canvasWidth = canvasWidth * devicePixelRatio;
canvasHeight = imageHeight / imageWidth * canvasWidth;

canvasImageInput.width = canvasWidth;
canvasImageInput.height = canvasHeight;

imageScaleFactor = canvasImageInput.width / imageInput.width;

console.log({imageWidth, imageHeight, canvasWidth, canvasHeight, devicePixelRatio, imageScaleFactor});

contextImageInput.drawImage(imageInput, 0, 0, canvasWidth, canvasHeight);

textAreaPixelblaze.value = "[]";
};

imageInput.src = objectUrl;
}

function onImageInputUndo() {
if (!imageInput) return;

const { leds } = parsePixelblazeText(textAreaPixelblaze.value);

if (leds.length < 1) return;

leds.pop();

textAreaPixelblaze.value = JSON.stringify(leds.map(({x, y}) => ([x, y])));

parsePixelblaze();

refreshImageMap();
}

function onImageCanvasClick(event) {
if (!imageInput) return;

const {x, y} = getCursorPosition(canvasImageInput, imageScaleFactor, event);

const { leds } = parsePixelblazeText(textAreaPixelblaze.value);

leds.push({index: leds.length, x, y});

textAreaPixelblaze.value = JSON.stringify(leds.map(({x, y}) => ([x, y])));

parsePixelblaze();

renderScale = false;
const scale = renderScale ? 256 : width > height ? width : height;
document.getElementById("buttonToggleScale").innerText = `Scale: ${scale}`;

showPreviewNumbers = true;
document.getElementById("iconShowPreviewNumbers").className = showPreviewNumbers ? "bi bi-check-square" : "bi bi-square";
inputPreviewFontSize.disabled = false;

showPreviewLEDs = false;
document.getElementById("iconShowPreviewLEDs").className = showPreviewLEDs ? "bi bi-check-square" : "bi bi-square";

refreshImageMap();
}

function refreshImageMap() {
const fontSize = inputPreviewFontSize.value;

context.font = `${fontSize}px monospace`;

drawImageMap(contextImageInput, canvasImageInput, imageInput, imageScaleFactor, leds, fontSize);
}

function onLinkCoordinates() {
copyLinkToClipboard(textAreaCoordinates, 'c', 'Coordinates');
}
Expand Down Expand Up @@ -166,14 +272,14 @@ function onPaletteChange() {
});
contextSelectedPalette.fillStyle = gradient;
contextSelectedPalette.fillRect(0, 0, canvasSelectedPalette.width, canvasSelectedPalette.height);
if (!running) window.requestAnimationFrame(render);
if (!running) window.requestAnimationFrame(renderPreview);
}

function onPatternChange() {
const code = getPatternCode(selectPattern.value);
inputPreviewCode.value = code;
onPreviewCodeChange();
if (!running) window.requestAnimationFrame(render);
if (!running) window.requestAnimationFrame(renderPreview);
}

function onPlayPauseClick() {
Expand Down Expand Up @@ -206,7 +312,7 @@ function onPreviewCodeChange() {
"speed",
code
);
window.requestAnimationFrame(render);
window.requestAnimationFrame(renderPreview);
} catch (error) {
handleRenderFunctionError(error);
return;
Expand All @@ -215,7 +321,7 @@ function onPreviewCodeChange() {

function onPreviewFontSizeChange() {
context.font = `${inputPreviewFontSize.value}px monospace`;
if (!running) window.requestAnimationFrame(render);
if (!running) window.requestAnimationFrame(renderPreview);
}

function onPreviewSpeedChange() {
Expand All @@ -241,7 +347,7 @@ function onShowPreviewLEDsChange() {

document.getElementById("iconShowPreviewLEDs").className = showPreviewLEDs ? "bi bi-check-square" : "bi bi-square";

if (!running) window.requestAnimationFrame(render);
if (!running) window.requestAnimationFrame(renderPreview);
}

function onShowPreviewNumbersChange() {
Expand All @@ -251,7 +357,7 @@ function onShowPreviewNumbersChange() {

inputPreviewFontSize.disabled = !showPreviewNumbers;

if (!running) window.requestAnimationFrame(render);
if (!running) window.requestAnimationFrame(renderPreview);
}

function onPreviewTextChange() {
Expand Down Expand Up @@ -283,7 +389,7 @@ function onToggleScale() {
renderScale = !renderScale;
const scale = renderScale ? 256 : width > height ? width : height;
document.getElementById("buttonToggleScale").innerText = `Scale: ${scale}`;
if (!running) window.requestAnimationFrame(render);
if (!running) window.requestAnimationFrame(renderPreview);
}

function onWindowResize() {
Expand All @@ -296,7 +402,7 @@ function onWindowResize() {
context.textAlign = "center";
context.textBaseline = "middle";

if (!running) window.requestAnimationFrame(render);
if (!running) window.requestAnimationFrame(renderPreview);
}

// functions
Expand All @@ -309,6 +415,8 @@ function addEventHandlers() {
inputPreviewFontSize.oninput = onPreviewFontSizeChange;
inputPreviewSpeed.oninput = onPreviewSpeedChange;

inputImage.onchange = onImageInputChange;

selectPalette.onchange = onPaletteChange;
selectPattern.onchange = onPatternChange;

Expand All @@ -332,6 +440,7 @@ function addEventHandlers() {
document.getElementById("buttonPreviousPalette").onclick = onPreviousPaletteClick;
document.getElementById("buttonPreviousPattern").onclick = onPreviousPatternClick;
document.getElementById("buttonToggleScale").onclick = onToggleScale;
document.getElementById("buttonImageInputUndo").onclick = onImageInputUndo;

document.getElementById("checkboxFlipX").onchange = flipX;
document.getElementById("checkboxFlipY").onchange = flipY;
Expand All @@ -351,13 +460,16 @@ function addEventHandlers() {
elem.parentElement.addEventListener("wheel", panzoom.zoomWithWheel);

document.getElementById("buttonReset").onclick = panzoom.reset;

canvasImageInput.onclick = onImageCanvasClick;
canvasImageInput.onkeydown = onCanvasImageInputKeyDown;
}

function configureCanvas2dContext() {
context.lineWidth = 1;
context.textAlign = "center";
context.textBaseline = "middle";
context.font = "1px monospace";
context.font = "20px monospace";
}

function ColorFromPalette(palette, index, brightness = 255) {
Expand Down Expand Up @@ -448,7 +560,9 @@ function generateCode() {

document.getElementById("codeStats").innerText = stats;

if (!running) window.requestAnimationFrame(render);
if (!running) window.requestAnimationFrame(renderPreview);

if (imageInput) refreshImageMap();

generatePixelblazeMap();
}
Expand Down Expand Up @@ -585,7 +699,7 @@ function handleRenderFunctionError(error, led) {
renderError.innerText = `Error: ${error.message}, LED: ${JSON.stringify(led)}.`;
}

function render() {
function renderPreview() {
if (renderFunction === undefined) return;

offset += offsetIncrement;
Expand Down Expand Up @@ -647,7 +761,7 @@ function render() {
}
}

if (running) window.requestAnimationFrame(render);
if (running) window.requestAnimationFrame(renderPreview);
}

function setRunning(value) {
Expand All @@ -656,18 +770,29 @@ function setRunning(value) {

buttonPlayPause.title = running ? "Pause" : "Play";

if (running) window.requestAnimationFrame(render);
if (running) window.requestAnimationFrame(renderPreview);
}

function initDefaultInputs() {
textAreaLayout.value = defaultLayout;

textAreaCoordinates.value = defaultCoordinates;

textAreaPixelblaze.value = defaultPixelblazeMap;
}

// initial setup function calls
initDefaultInputs();

addEventHandlers();

configureCanvas2dContext();
if (!parseQueryString()) {
parseLayout();
}
generateCode();
onPatternChange();
onPaletteChange();
window.requestAnimationFrame(render);
window.requestAnimationFrame(renderPreview);

onWindowResize();
Loading

0 comments on commit 47e5de2

Please sign in to comment.