qrframe/presets/Dots.js

119 wiersze
3.1 KiB
JavaScript

import { Module, getSeededRand } from "https://qrframe.kylezhe.ng/utils.js";
export const paramsSchema = {
Margin: {
type: "number",
min: 0,
max: 10,
step: 0.1,
default: 2,
},
Density: {
type: "number",
min: 2,
max: 10,
default: 4,
},
"Finder clarity": {
type: "number",
min: 1,
max: 1.5,
step: 0.1,
default: 1.3,
},
Foreground: {
type: "array",
resizable: true,
props: {
type: "color",
},
default: ["#f7158b", "#02d1fd", "#1f014b"],
},
Background: {
type: "color",
default: "#ffffff",
},
// See browser compatibility issues here
// https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode
"Mix blend mode": {
type: "select",
options: [
"normal",
"multiply",
"screen",
"overlay",
"darken",
"lighten",
"color-dodge",
"color-burn",
"hard-light",
"soft-light",
"difference",
"exclusion",
"hue",
"saturation",
"color",
"luminosity",
"plus-darker",
"plus-lighter",
],
},
Seed: {
type: "number",
min: 1,
max: 100,
default: 1,
},
};
export function renderSVG(qr, params) {
const unit = params["Density"];
const rand = getSeededRand(params["Seed"]);
const rangeStr = (min, max) => (rand() * (max - min) + min).toFixed(2);
const matrixWidth = qr.version * 4 + 17;
const margin = params["Margin"] * unit;
const colors = params["Foreground"];
const bg = params["Background"];
const size = matrixWidth * unit + 2 * margin;
let svg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="${-margin} ${-margin} ${size} ${size}">`;
const center = (matrixWidth * unit) / 2;
svg += `<defs><g id="dots">`;
const dotRadius = 1;
const dotSpace = 2.2;
const maxRadius = Math.sqrt((unit * unit * matrixWidth * matrixWidth) / 2);
for (let r = 0.1; r < maxRadius; r += dotSpace) {
const angleInc = dotSpace / r;
for (let theta = 0; theta < 2 * Math.PI - angleInc / 2; theta += angleInc) {
const x = r * Math.cos(theta);
const y = r * Math.sin(theta);
const qx = Math.floor((x + center) / unit);
const qy = Math.floor((y + center) / unit);
if (qx >= 0 && qx < matrixWidth && qy >= 0 && qy < matrixWidth) {
if (qr.matrix[qy * matrixWidth + qx] & Module.ON) {
const rad =
qr.matrix[qy * matrixWidth + qx] & Module.FINDER
? params["Finder clarity"]
: dotRadius;
svg += `<circle cx="${(center + x).toFixed(2)}" cy="${(center + y).toFixed(2)}" r="${rad}" />`;
}
}
}
}
svg += `</g></defs>`;
svg += `<rect x="${-margin}" y="${-margin}" width="${size}" height="${size}" fill="${bg}"/>`;
svg += `<g style="mix-blend-mode:${params["Mix blend mode"]}">`;
colors.forEach(
(color) =>
(svg += `<use href="#dots" fill="${color}" fill-opacity="0.75" transform="translate(${rangeStr(-1, 1)},${rangeStr(-1, 1)}) rotate(${rangeStr(-1, 1)})" transform-origin="${center} ${center}"/>`)
);
svg += `</g>`;
svg += `</svg>`;
return svg;
}