UI/machine/thumbnail: init random image generator for default thumbnail
This commit is contained in:
@@ -4,6 +4,7 @@ import { Menu } from "./Menu";
|
||||
import { activeURI } from "../App";
|
||||
import toast from "solid-toast";
|
||||
import { A, useNavigate } from "@solidjs/router";
|
||||
import { RndThumbnail } from "./noiseThumbnail";
|
||||
|
||||
type MachineDetails = SuccessQuery<"list_inventory_machines">["data"][string];
|
||||
|
||||
@@ -104,15 +105,8 @@ export const MachineListItem = (props: MachineListItemProps) => {
|
||||
return (
|
||||
<li>
|
||||
<div class="card card-side m-2">
|
||||
<figure class="pl-2">
|
||||
<span
|
||||
class="material-icons content-center text-5xl"
|
||||
classList={{
|
||||
"text-neutral-500": nixOnly,
|
||||
}}
|
||||
>
|
||||
devices_other
|
||||
</span>
|
||||
<figure class="h-fit rounded-xl border bg-def-2 border-def-5">
|
||||
<RndThumbnail name={name} width={220} height={120} />
|
||||
</figure>
|
||||
<div class="card-body flex-row justify-between ">
|
||||
<div class="flex flex-col">
|
||||
|
||||
120
pkgs/webview-ui/app/src/components/noiseThumbnail/index.tsx
Normal file
120
pkgs/webview-ui/app/src/components/noiseThumbnail/index.tsx
Normal file
@@ -0,0 +1,120 @@
|
||||
import { For } from "solid-js";
|
||||
|
||||
function mulberry32(seed: number) {
|
||||
return function () {
|
||||
let t = (seed += 0x6d2b79f5);
|
||||
t = Math.imul(t ^ (t >>> 15), 1 | t);
|
||||
t ^= t + Math.imul(t ^ (t >>> 7), 61 | t);
|
||||
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
|
||||
};
|
||||
}
|
||||
|
||||
function calculateCellColor(
|
||||
x: number,
|
||||
y: number,
|
||||
grid: number[][],
|
||||
rand: () => number,
|
||||
) {
|
||||
const rows = grid.length;
|
||||
const cols = grid[0].length;
|
||||
|
||||
// Get the values of neighboring cells
|
||||
const neighbors = [
|
||||
grid[y][(x - 1 + cols) % cols], // Left
|
||||
grid[y][(x + 1) % cols], // Right
|
||||
grid[(y - 1 + rows) % rows][x], // Top
|
||||
grid[(y + 1) % rows][x], // Bottom
|
||||
];
|
||||
|
||||
const makeValue = (threshold: number, wanted: number) =>
|
||||
rand() > threshold ? Math.floor(rand() * 50) : wanted;
|
||||
|
||||
// Calculate the sum of neighbors
|
||||
const neighborSum = neighbors.reduce((sum, val) => sum + val, 0);
|
||||
// Introduce a hard cutoff for fewer intermediate values
|
||||
if (neighborSum < 1) {
|
||||
// Mostly dark squares
|
||||
// return Math.floor(rand() * 50); // Darker square
|
||||
return makeValue(0.9, Math.floor(rand() * 50));
|
||||
} else if (neighborSum >= 3) {
|
||||
// Mostly bright squares
|
||||
// return Math.floor(200 + rand() * 55); // Bright square
|
||||
return makeValue(0.9, Math.floor(200 + rand() * 55));
|
||||
} else {
|
||||
// Rare intermediate values
|
||||
return makeValue(0.4, Math.floor(100 + rand() * 50));
|
||||
}
|
||||
}
|
||||
|
||||
function generatePatternedImage(seed: number, width = 300, height = 150) {
|
||||
const rand = mulberry32(seed);
|
||||
const rowSize = 1 + Math.floor((rand() * width) / 10);
|
||||
const colSize = 1 + Math.floor((rand() * height) / 10);
|
||||
const cols = Math.floor(width / colSize);
|
||||
const rows = Math.floor(height / rowSize);
|
||||
|
||||
// Initialize a 2D grid with random values (0 or 1)
|
||||
const grid = Array.from({ length: rows }, () =>
|
||||
Array.from({ length: cols }, () => (rand() > 0.5 ? 1 : 0)),
|
||||
);
|
||||
|
||||
const canvas = document.createElement("canvas");
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
const ctx = canvas.getContext("2d");
|
||||
|
||||
if (!ctx) {
|
||||
throw new Error("Could not get 2d context");
|
||||
}
|
||||
|
||||
const centerX = width / 2;
|
||||
const centerY = height / 2;
|
||||
const totalCells = rows * cols;
|
||||
for (let i = 0; i < totalCells; i++) {
|
||||
// Calculate polar coordinates
|
||||
const angle = (i / totalCells) * Math.PI * 2 * rand() * 360; // Increase the spiral's density
|
||||
const radius = Math.sqrt(i) * rand() * 4; // Controls how tightly the spiral is packed
|
||||
|
||||
// Convert polar to Cartesian coordinates
|
||||
const x = Math.floor(centerX + radius * Math.cos(angle));
|
||||
const y = Math.floor(centerY + radius * Math.sin(angle));
|
||||
|
||||
// Find grid coordinates
|
||||
const col = Math.floor(x / colSize);
|
||||
const row = Math.floor(y / rowSize);
|
||||
|
||||
// Ensure the cell is within bounds
|
||||
if (col >= 0 && col < cols && row >= 0 && row < rows) {
|
||||
const colorValue = calculateCellColor(col, row, grid, rand);
|
||||
ctx.fillStyle = `rgb(${colorValue}, ${colorValue}, ${colorValue})`;
|
||||
ctx.fillRect(x, y, colSize, rowSize);
|
||||
}
|
||||
}
|
||||
|
||||
return canvas.toDataURL();
|
||||
}
|
||||
|
||||
interface RndThumbnailProps {
|
||||
name: string;
|
||||
width?: number;
|
||||
height?: number;
|
||||
}
|
||||
export const RndThumbnail = (props: RndThumbnailProps) => {
|
||||
const { name } = props;
|
||||
const seed = Array.from(name).reduce(
|
||||
(acc, char) => acc + char.charCodeAt(0),
|
||||
0,
|
||||
); // Seed from name
|
||||
const imageSrc = generatePatternedImage(seed, props.width, props.height);
|
||||
return <img src={imageSrc} alt={name} />;
|
||||
};
|
||||
|
||||
export const RndThumbnailShow = () => {
|
||||
const names = ["hsjobeki", "mic92", "lassulus", "D", "A", "D", "B", "C"];
|
||||
|
||||
return (
|
||||
<div class="grid grid-cols-4">
|
||||
<For each={names}>{(name) => <RndThumbnail name={name} />}</For>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user