Files
snk/svg-only/dist/340.index.js
release bot 29c7ee48ec 📦 2.1.0
2022-11-03 09:06:43 +00:00

325 lines
10 KiB
JavaScript

"use strict";
exports.id = 340;
exports.ids = [340];
exports.modules = {
/***/ 8340:
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
// ESM COMPAT FLAG
__webpack_require__.r(__webpack_exports__);
// EXPORTS
__webpack_require__.d(__webpack_exports__, {
"createSvg": () => (/* binding */ createSvg)
});
// EXTERNAL MODULE: ../types/grid.ts
var types_grid = __webpack_require__(2881);
// EXTERNAL MODULE: ../types/snake.ts
var types_snake = __webpack_require__(9347);
;// CONCATENATED MODULE: ../svg-creator/xml-utils.ts
const h = (element, attributes) => `<${element} ${toAttribute(attributes)}/>`;
const toAttribute = (o) => Object.entries(o)
.filter(([, value]) => value !== null)
.map(([name, value]) => `${name}="${value}"`)
.join(" ");
;// CONCATENATED MODULE: ../svg-creator/css-utils.ts
const percent = (x) => parseFloat((x * 100).toFixed(2)).toString() + "%";
const mergeKeyFrames = (keyframes) => {
const s = new Map();
for (const { t, style } of keyframes) {
s.set(style, [...(s.get(style) ?? []), t]);
}
return Array.from(s.entries())
.map(([style, ts]) => ({ style, ts }))
.sort((a, b) => a.ts[0] - b.ts[0]);
};
/**
* generate the keyframe animation from a list of keyframe
*/
const createAnimation = (name, keyframes) => `@keyframes ${name}{` +
mergeKeyFrames(keyframes)
.map(({ style, ts }) => ts.map(percent).join(",") + `{${style}}`)
.join("") +
"}";
/**
* remove white spaces
*/
const minifyCss = (css) => css
.replace(/\s+/g, " ")
.replace(/.\s+[,;:{}()]/g, (a) => a.replace(/\s+/g, ""))
.replace(/[,;:{}()]\s+./g, (a) => a.replace(/\s+/g, ""))
.replace(/.\s+[,;:{}()]/g, (a) => a.replace(/\s+/g, ""))
.replace(/[,;:{}()]\s+./g, (a) => a.replace(/\s+/g, ""))
.replace(/\;\s*\}/g, "}")
.trim();
;// CONCATENATED MODULE: ../svg-creator/snake.ts
const lerp = (k, a, b) => (1 - k) * a + k * b;
const createSnake = (chain, { sizeCell, sizeDot }, duration) => {
const snakeN = chain[0] ? (0,types_snake/* getSnakeLength */.JJ)(chain[0]) : 0;
const snakeParts = Array.from({ length: snakeN }, () => []);
for (const snake of chain) {
const cells = (0,types_snake/* snakeToCells */.Ks)(snake);
for (let i = cells.length; i--;)
snakeParts[i].push(cells[i]);
}
const svgElements = snakeParts.map((_, i, { length }) => {
// compute snake part size
const dMin = sizeDot * 0.8;
const dMax = sizeCell * 0.9;
const iMax = Math.min(4, length);
const u = (1 - Math.min(i, iMax) / iMax) ** 2;
const s = lerp(u, dMin, dMax);
const m = (sizeCell - s) / 2;
const r = Math.min(4.5, (4 * s) / sizeDot);
return h("rect", {
class: `s s${i}`,
x: m.toFixed(1),
y: m.toFixed(1),
width: s.toFixed(1),
height: s.toFixed(1),
rx: r.toFixed(1),
ry: r.toFixed(1),
});
});
const transform = ({ x, y }) => `transform:translate(${x * sizeCell}px,${y * sizeCell}px)`;
const styles = [
`.s{
shape-rendering: geometricPrecision;
fill: var(--cs);
animation: none linear ${duration}ms infinite
}`,
...snakeParts.map((positions, i) => {
const id = `s${i}`;
const animationName = id;
const keyframes = removeInterpolatedPositions(positions.map((tr, i, { length }) => ({ ...tr, t: i / length }))).map(({ t, ...p }) => ({ t, style: transform(p) }));
return [
createAnimation(animationName, keyframes),
`.s.${id}{
${transform(positions[0])};
animation-name: ${animationName}
}`,
];
}),
].flat();
return { svgElements, styles };
};
const removeInterpolatedPositions = (arr) => arr.filter((u, i, arr) => {
if (i - 1 < 0 || i + 1 >= arr.length)
return true;
const a = arr[i - 1];
const b = arr[i + 1];
const ex = (a.x + b.x) / 2;
const ey = (a.y + b.y) / 2;
// return true;
return !(Math.abs(ex - u.x) < 0.01 && Math.abs(ey - u.y) < 0.01);
});
;// CONCATENATED MODULE: ../svg-creator/grid.ts
const createGrid = (cells, { sizeDotBorderRadius, sizeDot, sizeCell }, duration) => {
const svgElements = [];
const styles = [
`.c{
shape-rendering: geometricPrecision;
fill: var(--ce);
stroke-width: 1px;
stroke: var(--cb);
animation: none ${duration}ms linear infinite;
width: ${sizeDot}px;
height: ${sizeDot}px;
}`,
];
let i = 0;
for (const { x, y, color, t } of cells) {
const id = t && "c" + (i++).toString(36);
const m = (sizeCell - sizeDot) / 2;
if (t !== null && id) {
const animationName = id;
styles.push(createAnimation(animationName, [
{ t: t - 0.0001, style: `fill:var(--c${color})` },
{ t: t + 0.0001, style: `fill:var(--ce)` },
{ t: 1, style: `fill:var(--ce)` },
]), `.c.${id}{
fill: var(--c${color});
animation-name: ${animationName}
}`);
}
svgElements.push(h("rect", {
class: ["c", id].filter(Boolean).join(" "),
x: x * sizeCell + m,
y: y * sizeCell + m,
rx: sizeDotBorderRadius,
ry: sizeDotBorderRadius,
}));
}
return { svgElements, styles };
};
;// CONCATENATED MODULE: ../svg-creator/stack.ts
const createStack = (cells, { sizeDot }, width, y, duration) => {
const svgElements = [];
const styles = [
`.u{
transform-origin: 0 0;
transform: scale(0,1);
animation: none linear ${duration}ms infinite;
}`,
];
const stack = cells
.slice()
.filter((a) => a.t !== null)
.sort((a, b) => a.t - b.t);
const blocks = [];
stack.forEach(({ color, t }) => {
const latest = blocks[blocks.length - 1];
if (latest?.color === color)
latest.ts.push(t);
else
blocks.push({ color, ts: [t] });
});
const m = width / stack.length;
let i = 0;
let nx = 0;
for (const { color, ts } of blocks) {
const id = "u" + (i++).toString(36);
const animationName = id;
const x = (nx * m).toFixed(1);
nx += ts.length;
svgElements.push(h("rect", {
class: `u ${id}`,
height: sizeDot,
width: (ts.length * m + 0.6).toFixed(1),
x,
y,
}));
styles.push(createAnimation(animationName, [
...ts
.map((t, i, { length }) => [
{ scale: i / length, t: t - 0.0001 },
{ scale: (i + 1) / length, t: t + 0.0001 },
])
.flat(),
{ scale: 1, t: 1 },
].map(({ scale, t }) => ({
t,
style: `transform:scale(${scale.toFixed(3)},1)`,
}))), `.u.${id} {
fill: var(--c${color});
animation-name: ${animationName};
transform-origin: ${x}px 0
}
`);
}
return { svgElements, styles };
};
;// CONCATENATED MODULE: ../svg-creator/index.ts
const getCellsFromGrid = ({ width, height }) => Array.from({ length: width }, (_, x) => Array.from({ length: height }, (_, y) => ({ x, y }))).flat();
const createLivingCells = (grid0, chain, cells) => {
const livingCells = (cells ?? getCellsFromGrid(grid0)).map(({ x, y }) => ({
x,
y,
t: null,
color: (0,types_grid/* getColor */.Lq)(grid0, x, y),
}));
const grid = (0,types_grid/* copyGrid */.VJ)(grid0);
for (let i = 0; i < chain.length; i++) {
const snake = chain[i];
const x = (0,types_snake/* getHeadX */.If)(snake);
const y = (0,types_snake/* getHeadY */.IP)(snake);
if ((0,types_grid/* isInside */.V0)(grid, x, y) && !(0,types_grid/* isEmpty */.xb)((0,types_grid/* getColor */.Lq)(grid, x, y))) {
(0,types_grid/* setColorEmpty */.Dy)(grid, x, y);
const cell = livingCells.find((c) => c.x === x && c.y === y);
cell.t = i / chain.length;
}
}
return livingCells;
};
const createSvg = (grid, cells, chain, drawOptions, animationOptions) => {
const width = (grid.width + 2) * drawOptions.sizeCell;
const height = (grid.height + 5) * drawOptions.sizeCell;
const duration = animationOptions.frameDuration * chain.length;
const livingCells = createLivingCells(grid, chain, cells);
const elements = [
createGrid(livingCells, drawOptions, duration),
createStack(livingCells, drawOptions, grid.width * drawOptions.sizeCell, (grid.height + 2) * drawOptions.sizeCell, duration),
createSnake(chain, drawOptions, duration),
];
const viewBox = [
-drawOptions.sizeCell,
-drawOptions.sizeCell * 2,
width,
height,
].join(" ");
const style = generateColorVar(drawOptions) +
elements
.map((e) => e.styles)
.flat()
.join("\n");
const svg = [
h("svg", {
viewBox,
width,
height,
xmlns: "http://www.w3.org/2000/svg",
}).replace("/>", ">"),
"<desc>",
"Generated with https://github.com/Platane/snk",
"</desc>",
"<style>",
optimizeCss(style),
"</style>",
...elements.map((e) => e.svgElements).flat(),
"</svg>",
].join("");
return optimizeSvg(svg);
};
const optimizeCss = (css) => minifyCss(css);
const optimizeSvg = (svg) => svg;
const generateColorVar = (drawOptions) => `
:root {
--cb: ${drawOptions.colorDotBorder};
--cs: ${drawOptions.colorSnake};
--ce: ${drawOptions.colorEmpty};
${Object.entries(drawOptions.colorDots)
.map(([i, color]) => `--c${i}:${color};`)
.join("")}
}
` +
(drawOptions.dark
? `
@media (prefers-color-scheme: dark) {
:root {
--cb: ${drawOptions.dark.colorDotBorder || drawOptions.colorDotBorder};
--cs: ${drawOptions.dark.colorSnake || drawOptions.colorSnake};
--ce: ${drawOptions.dark.colorEmpty};
${Object.entries(drawOptions.dark.colorDots)
.map(([i, color]) => `--c${i}:${color};`)
.join("")}
}
}
`
: "");
/***/ })
};
;