🚀 improve svg generation

This commit is contained in:
platane
2020-11-04 09:17:19 +01:00
parent 24e7a1ceec
commit 817362d1dd
5 changed files with 79 additions and 50 deletions

View File

@@ -24,7 +24,7 @@ try {
} catch (err) {}
for (const [key, grid] of Object.entries(grids))
it(`should generate ${key} gif`, () => {
it(`should generate ${key} svg`, () => {
const chain = [snake, ...getBestRoute(grid, snake)!];
const gif = createSvg(grid, chain, drawOptions, gifOptions);

View File

@@ -27,13 +27,14 @@ export const createGrid = (
) => {
const svgElements: string[] = [];
const styles = [
`rect.c{
`.c{
shape-rendering: geometricPrecision;
outline: 1px solid ${colorBorder};
outline-offset: -1px;
rx: ${sizeBorderRadius};
ry: ${sizeBorderRadius};
fill:${colorEmpty}
fill:${colorEmpty};
stroke-width: 1px;
stroke: ${colorBorder};
animation: none ${duration}ms linear infinite;
}`,
];
@@ -55,14 +56,13 @@ export const createGrid = (
`${percent(t + 0.0001)}%,100%{fill:${colorEmpty}}` +
"}",
`#${id}{fill:${fill};animation: ${animationName} linear ${duration}ms infinite}`
`.c.${id}{fill:${fill};animation-name: ${animationName}}`
);
}
svgElements.push(
h("rect", {
id,
class: "c",
class: ["c", id].filter(Boolean).join(" "),
x: x * s + m,
y: y * s + m,
width: d,

View File

@@ -25,26 +25,20 @@ export type Options = {
cells?: Point[];
};
const createCells = ({ width, height }: Grid) =>
const getCellsFromGrid = ({ width, height }: Grid) =>
Array.from({ length: width }, (_, x) =>
Array.from({ length: height }, (_, y) => ({ x, y }))
).flat();
export const createSvg = (
const createLivingCells = (
grid0: Grid,
chain: Snake[],
drawOptions: Options,
gifOptions: { frameDuration: number }
drawOptions: Options
) => {
const width = (grid0.width + 2) * drawOptions.sizeCell;
const height = (grid0.height + 5) * drawOptions.sizeCell;
const duration = gifOptions.frameDuration * chain.length;
const cells: (Point & {
t: number | null;
color: Color | Empty;
})[] = (drawOptions.cells ?? createCells(grid0)).map(({ x, y }) => ({
})[] = (drawOptions.cells ?? getCellsFromGrid(grid0)).map(({ x, y }) => ({
x,
y,
t: null,
@@ -64,13 +58,29 @@ export const createSvg = (
}
}
return cells;
};
export const createSvg = (
grid: Grid,
chain: Snake[],
drawOptions: Options,
gifOptions: { frameDuration: number }
) => {
const width = (grid.width + 2) * drawOptions.sizeCell;
const height = (grid.height + 5) * drawOptions.sizeCell;
const duration = gifOptions.frameDuration * chain.length;
const cells = createLivingCells(grid, chain, drawOptions);
const elements = [
createGrid(cells, drawOptions, duration),
createStack(
cells,
drawOptions,
grid0.width * drawOptions.sizeCell,
(grid0.height + 2) * drawOptions.sizeCell,
grid.width * drawOptions.sizeCell,
(grid.height + 2) * drawOptions.sizeCell,
duration
),
createSnake(chain, drawOptions, duration),
@@ -83,21 +93,32 @@ export const createSvg = (
height,
].join(" ");
return [
const style = elements
.map((e) => e.styles)
.flat()
.join("");
const svg = [
`<svg
${toAttribute({
viewBox,
width,
height,
xmlns: "http://www.w3.org/2000/svg",
})}
>`,
${toAttribute({
viewBox,
width,
height,
xmlns: "http://www.w3.org/2000/svg",
})}
>`,
"<style>",
...elements.map((e) => e.styles).flat(),
optimizeCss(style),
"</style>",
...elements.map((e) => e.svgElements).flat(),
"</svg>",
].join("\n");
].join("");
return optimizeSvg(svg);
};
const optimizeCss = (css: string) => css;
const optimizeSvg = (svg: string) => svg;

View File

@@ -42,17 +42,16 @@ export const createSnake = (
const m = (sizeCell - s) / 2;
const r = Math.min(4.5, (4 * s) / sizeDot).toFixed(2);
const r = Math.min(4.5, (4 * s) / sizeDot);
return h("rect", {
class: "s",
id: `s${i}`,
x: m,
y: m,
width: s,
height: s,
rx: r,
ry: r,
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),
});
});
@@ -60,9 +59,10 @@ export const createSnake = (
`transform:translate(${x * sizeCell}px,${y * sizeCell}px)`;
const styles = [
`rect.s{
shape-rendering: geometricPrecision;
`.s{
shape-rendering:geometricPrecision;
fill:${colorSnake};
animation: none linear ${duration}ms infinite
}`,
...snakeParts.map((positions, i) => {
@@ -78,10 +78,7 @@ export const createSnake = (
.join("") +
"}",
`#${id}{` +
`${transform(positions[0])};` +
`animation: ${animationName} linear ${duration}ms infinite` +
"}",
`.s.${id}{${transform(positions[0])};animation-name: ${animationName}}`,
];
}),
].flat();

View File

@@ -16,7 +16,12 @@ export const createStack = (
duration: number
) => {
const svgElements: string[] = [];
const styles = [];
const styles = [
`.u{
animation: none linear ${duration}ms infinite;
fill:transparent;
}`,
];
const stack = cells
.slice()
@@ -26,14 +31,20 @@ export const createStack = (
const m = width / stack.length;
let i = 0;
for (const { color, t } of stack) {
const x = ((i * width) / stack.length).toFixed(2);
const id = "t" + (i++).toString(36);
const x = (i * width) / stack.length;
const id = "u" + (i++).toString(36);
const animationName = "a" + id;
// @ts-ignore
const fill = colorDots[color];
svgElements.push(
h("rect", { id, height: sizeDot, width: (m + 0.6).toFixed(2), x, y })
h("rect", {
class: `u ${id}`,
height: sizeDot,
width: (m + 0.6).toFixed(1),
x: x.toFixed(1),
y,
})
);
styles.push(
`@keyframes ${animationName} {` +
@@ -41,7 +52,7 @@ export const createStack = (
`${percent(t + 0.0001)}%,100%{fill:${fill}}` +
"}",
`#${id}{fill:transparent;animation: ${animationName} linear ${duration}ms infinite}`
`.u.${id}{animation-name:${animationName}}`
);
}