♻️ refacto: rename options
This commit is contained in:
@@ -2,6 +2,10 @@
|
|||||||
|
|
||||||
exports[`should parse /out.svg?{"color_snake":"yellow","color_dots":["#000","#111","#222","#333","#444"]} 1`] = `
|
exports[`should parse /out.svg?{"color_snake":"yellow","color_dots":["#000","#111","#222","#333","#444"]} 1`] = `
|
||||||
Object {
|
Object {
|
||||||
|
"animationOptions": Object {
|
||||||
|
"frameDuration": 100,
|
||||||
|
"step": 1,
|
||||||
|
},
|
||||||
"drawOptions": Object {
|
"drawOptions": Object {
|
||||||
"colorDotBorder": "#1b1f230a",
|
"colorDotBorder": "#1b1f230a",
|
||||||
"colorDots": Array [
|
"colorDots": Array [
|
||||||
@@ -20,15 +24,15 @@ Object {
|
|||||||
},
|
},
|
||||||
"filename": "/out.svg",
|
"filename": "/out.svg",
|
||||||
"format": "svg",
|
"format": "svg",
|
||||||
"gifOptions": Object {
|
|
||||||
"frameDuration": 100,
|
|
||||||
"step": 1,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`should parse /out.svg?color_snake=orange&color_dots=#000,#111,#222,#333,#444 1`] = `
|
exports[`should parse /out.svg?color_snake=orange&color_dots=#000,#111,#222,#333,#444 1`] = `
|
||||||
Object {
|
Object {
|
||||||
|
"animationOptions": Object {
|
||||||
|
"frameDuration": 100,
|
||||||
|
"step": 1,
|
||||||
|
},
|
||||||
"drawOptions": Object {
|
"drawOptions": Object {
|
||||||
"colorDotBorder": "#1b1f230a",
|
"colorDotBorder": "#1b1f230a",
|
||||||
"colorDots": Array [
|
"colorDots": Array [
|
||||||
@@ -47,15 +51,15 @@ Object {
|
|||||||
},
|
},
|
||||||
"filename": "/out.svg",
|
"filename": "/out.svg",
|
||||||
"format": "svg",
|
"format": "svg",
|
||||||
"gifOptions": Object {
|
|
||||||
"frameDuration": 100,
|
|
||||||
"step": 1,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`should parse /out.svg?color_snake=orange&color_dots=#000,#111,#222,#333,#444&dark_color_dots=#a00,#a11,#a22,#a33,#a44 1`] = `
|
exports[`should parse /out.svg?color_snake=orange&color_dots=#000,#111,#222,#333,#444&dark_color_dots=#a00,#a11,#a22,#a33,#a44 1`] = `
|
||||||
Object {
|
Object {
|
||||||
|
"animationOptions": Object {
|
||||||
|
"frameDuration": 100,
|
||||||
|
"step": 1,
|
||||||
|
},
|
||||||
"drawOptions": Object {
|
"drawOptions": Object {
|
||||||
"colorDotBorder": "#1b1f230a",
|
"colorDotBorder": "#1b1f230a",
|
||||||
"colorDots": Array [
|
"colorDots": Array [
|
||||||
@@ -83,15 +87,15 @@ Object {
|
|||||||
},
|
},
|
||||||
"filename": "/out.svg",
|
"filename": "/out.svg",
|
||||||
"format": "svg",
|
"format": "svg",
|
||||||
"gifOptions": Object {
|
|
||||||
"frameDuration": 100,
|
|
||||||
"step": 1,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`should parse path/to/out.gif 1`] = `
|
exports[`should parse path/to/out.gif 1`] = `
|
||||||
Object {
|
Object {
|
||||||
|
"animationOptions": Object {
|
||||||
|
"frameDuration": 100,
|
||||||
|
"step": 1,
|
||||||
|
},
|
||||||
"drawOptions": Object {
|
"drawOptions": Object {
|
||||||
"colorDotBorder": "#1b1f230a",
|
"colorDotBorder": "#1b1f230a",
|
||||||
"colorDots": Array [
|
"colorDots": Array [
|
||||||
@@ -121,9 +125,5 @@ Object {
|
|||||||
},
|
},
|
||||||
"filename": "path/to/out.gif",
|
"filename": "path/to/out.gif",
|
||||||
"format": "gif",
|
"format": "gif",
|
||||||
"gifOptions": Object {
|
|
||||||
"frameDuration": 100,
|
|
||||||
"step": 1,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -3,17 +3,15 @@ import { userContributionToGrid } from "./userContributionToGrid";
|
|||||||
import { getBestRoute } from "@snk/solver/getBestRoute";
|
import { getBestRoute } from "@snk/solver/getBestRoute";
|
||||||
import { snake4 } from "@snk/types/__fixtures__/snake";
|
import { snake4 } from "@snk/types/__fixtures__/snake";
|
||||||
import { getPathToPose } from "@snk/solver/getPathToPose";
|
import { getPathToPose } from "@snk/solver/getPathToPose";
|
||||||
import { Options as DrawOptions } from "@snk/svg-creator";
|
import type { DrawOptions as DrawOptions } from "@snk/svg-creator";
|
||||||
|
import type { AnimationOptions } from "@snk/gif-creator";
|
||||||
|
|
||||||
export const generateContributionSnake = async (
|
export const generateContributionSnake = async (
|
||||||
userName: string,
|
userName: string,
|
||||||
outputs: ({
|
outputs: ({
|
||||||
format: "svg" | "gif";
|
format: "svg" | "gif";
|
||||||
drawOptions: DrawOptions;
|
drawOptions: DrawOptions;
|
||||||
gifOptions: {
|
animationOptions: AnimationOptions;
|
||||||
frameDuration: number;
|
|
||||||
step: number;
|
|
||||||
};
|
|
||||||
} | null)[]
|
} | null)[]
|
||||||
) => {
|
) => {
|
||||||
console.log("🎣 fetching github user contribution");
|
console.log("🎣 fetching github user contribution");
|
||||||
@@ -29,17 +27,23 @@ export const generateContributionSnake = async (
|
|||||||
return Promise.all(
|
return Promise.all(
|
||||||
outputs.map(async (out, i) => {
|
outputs.map(async (out, i) => {
|
||||||
if (!out) return;
|
if (!out) return;
|
||||||
const { format, drawOptions, gifOptions } = out;
|
const { format, drawOptions, animationOptions } = out;
|
||||||
switch (format) {
|
switch (format) {
|
||||||
case "svg": {
|
case "svg": {
|
||||||
console.log(`🖌 creating svg (outputs[${i}])`);
|
console.log(`🖌 creating svg (outputs[${i}])`);
|
||||||
const { createSvg } = await import("@snk/svg-creator");
|
const { createSvg } = await import("@snk/svg-creator");
|
||||||
return createSvg(grid, chain, drawOptions, gifOptions);
|
return createSvg(grid, cells, chain, drawOptions, animationOptions);
|
||||||
}
|
}
|
||||||
case "gif": {
|
case "gif": {
|
||||||
console.log(`📹 creating gif (outputs[${i}])`);
|
console.log(`📹 creating gif (outputs[${i}])`);
|
||||||
const { createGif } = await import("@snk/gif-creator");
|
const { createGif } = await import("@snk/gif-creator");
|
||||||
return await createGif(grid, chain, drawOptions, gifOptions);
|
return await createGif(
|
||||||
|
grid,
|
||||||
|
cells,
|
||||||
|
chain,
|
||||||
|
drawOptions,
|
||||||
|
animationOptions
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { Options as DrawOptions } from "@snk/svg-creator";
|
import type { AnimationOptions } from "@snk/gif-creator";
|
||||||
|
import type { DrawOptions as DrawOptions } from "@snk/svg-creator";
|
||||||
import { palettes } from "./palettes";
|
import { palettes } from "./palettes";
|
||||||
|
|
||||||
export const parseOutputsOption = (lines: string[]) => lines.map(parseEntry);
|
export const parseOutputsOption = (lines: string[]) => lines.map(parseEntry);
|
||||||
@@ -29,7 +30,7 @@ export const parseEntry = (entry: string) => {
|
|||||||
sizeDot: 12,
|
sizeDot: 12,
|
||||||
...palettes["default"],
|
...palettes["default"],
|
||||||
};
|
};
|
||||||
const gifOptions = { step: 1, frameDuration: 100 };
|
const animationOptions: AnimationOptions = { step: 1, frameDuration: 100 };
|
||||||
|
|
||||||
{
|
{
|
||||||
const palette = palettes[sp.get("palette")!];
|
const palette = palettes[sp.get("palette")!];
|
||||||
@@ -62,5 +63,10 @@ export const parseEntry = (entry: string) => {
|
|||||||
if (sp.has("dark_color_snake") && drawOptions.dark)
|
if (sp.has("dark_color_snake") && drawOptions.dark)
|
||||||
drawOptions.dark.colorSnake = sp.get("color_snake")!;
|
drawOptions.dark.colorSnake = sp.get("color_snake")!;
|
||||||
|
|
||||||
return { filename, format: format as "svg" | "gif", drawOptions, gifOptions };
|
return {
|
||||||
|
filename,
|
||||||
|
format: format as "svg" | "gif",
|
||||||
|
drawOptions,
|
||||||
|
animationOptions,
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Options as DrawOptions } from "@snk/svg-creator";
|
import { DrawOptions as DrawOptions } from "@snk/svg-creator";
|
||||||
|
|
||||||
export const palettes: Record<
|
export const palettes: Record<
|
||||||
string,
|
string,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Color, Grid } from "@snk/types/grid";
|
import { Color, Grid } from "@snk/types/grid";
|
||||||
import { drawLerpWorld, drawWorld } from "@snk/draw/drawWorld";
|
import { drawLerpWorld, drawWorld } from "@snk/draw/drawWorld";
|
||||||
import { Snake } from "@snk/types/snake";
|
import { Snake } from "@snk/types/snake";
|
||||||
import type { Options as DrawOptions } from "@snk/svg-creator";
|
import type { DrawOptions as DrawOptions } from "@snk/svg-creator";
|
||||||
|
|
||||||
export const drawOptions: DrawOptions = {
|
export const drawOptions: DrawOptions = {
|
||||||
sizeDotBorderRadius: 2,
|
sizeDotBorderRadius: 2,
|
||||||
@@ -68,7 +68,7 @@ export const createCanvas = ({
|
|||||||
|
|
||||||
const draw = (grid: Grid, snake: Snake, stack: Color[]) => {
|
const draw = (grid: Grid, snake: Snake, stack: Color[]) => {
|
||||||
ctx.clearRect(0, 0, 9999, 9999);
|
ctx.clearRect(0, 0, 9999, 9999);
|
||||||
drawWorld(ctx, grid, snake, stack, drawOptions);
|
drawWorld(ctx, grid, null, snake, stack, drawOptions);
|
||||||
};
|
};
|
||||||
|
|
||||||
const drawLerp = (
|
const drawLerp = (
|
||||||
@@ -79,7 +79,7 @@ export const createCanvas = ({
|
|||||||
k: number
|
k: number
|
||||||
) => {
|
) => {
|
||||||
ctx.clearRect(0, 0, 9999, 9999);
|
ctx.clearRect(0, 0, 9999, 9999);
|
||||||
drawLerpWorld(ctx, grid, snake0, snake1, stack, k, drawOptions);
|
drawLerpWorld(ctx, grid, null, snake0, snake1, stack, k, drawOptions);
|
||||||
};
|
};
|
||||||
|
|
||||||
const highlightCell = (x: number, y: number, color = "orange") => {
|
const highlightCell = (x: number, y: number, color = "orange") => {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { step } from "@snk/solver/step";
|
|||||||
import { isStableAndBound, stepSpring } from "./springUtils";
|
import { isStableAndBound, stepSpring } from "./springUtils";
|
||||||
import type { Res } from "@snk/github-user-contribution";
|
import type { Res } from "@snk/github-user-contribution";
|
||||||
import type { Snake } from "@snk/types/snake";
|
import type { Snake } from "@snk/types/snake";
|
||||||
|
import type { Point } from "@snk/types/point";
|
||||||
import {
|
import {
|
||||||
drawLerpWorld,
|
drawLerpWorld,
|
||||||
getCanvasWorldSize,
|
getCanvasWorldSize,
|
||||||
@@ -12,6 +13,7 @@ import { userContributionToGrid } from "@snk/action/userContributionToGrid";
|
|||||||
import { createSvg } from "@snk/svg-creator";
|
import { createSvg } from "@snk/svg-creator";
|
||||||
import { createRpcClient } from "./worker-utils";
|
import { createRpcClient } from "./worker-utils";
|
||||||
import type { API as WorkerAPI } from "./demo.interactive.worker";
|
import type { API as WorkerAPI } from "./demo.interactive.worker";
|
||||||
|
import { AnimationOptions } from "@snk/gif-creator";
|
||||||
|
|
||||||
const createForm = ({
|
const createForm = ({
|
||||||
onSubmit,
|
onSubmit,
|
||||||
@@ -116,10 +118,12 @@ const createGithubProfile = () => {
|
|||||||
const createViewer = ({
|
const createViewer = ({
|
||||||
grid0,
|
grid0,
|
||||||
chain,
|
chain,
|
||||||
|
cells,
|
||||||
drawOptions,
|
drawOptions,
|
||||||
}: {
|
}: {
|
||||||
grid0: Grid;
|
grid0: Grid;
|
||||||
chain: Snake[];
|
chain: Snake[];
|
||||||
|
cells: Point[];
|
||||||
drawOptions: DrawOptions;
|
drawOptions: DrawOptions;
|
||||||
}) => {
|
}) => {
|
||||||
//
|
//
|
||||||
@@ -159,7 +163,7 @@ const createViewer = ({
|
|||||||
const k = spring.x % 1;
|
const k = spring.x % 1;
|
||||||
|
|
||||||
ctx.clearRect(0, 0, 9999, 9999);
|
ctx.clearRect(0, 0, 9999, 9999);
|
||||||
drawLerpWorld(ctx, grid, snake0, snake1, stack, k, drawOptions);
|
drawLerpWorld(ctx, grid, null, snake0, snake1, stack, k, drawOptions);
|
||||||
|
|
||||||
if (!stable) animationFrame = requestAnimationFrame(loop);
|
if (!stable) animationFrame = requestAnimationFrame(loop);
|
||||||
};
|
};
|
||||||
@@ -189,9 +193,9 @@ const createViewer = ({
|
|||||||
//
|
//
|
||||||
// svg
|
// svg
|
||||||
const svgLink = document.createElement("a");
|
const svgLink = document.createElement("a");
|
||||||
const svgString = createSvg(grid0, chain, drawOptions, {
|
const svgString = createSvg(grid0, cells, chain, drawOptions, {
|
||||||
frameDuration: 100,
|
frameDuration: 100,
|
||||||
});
|
} as AnimationOptions);
|
||||||
const svgImageUri = `data:image/*;charset=utf-8;base64,${btoa(svgString)}`;
|
const svgImageUri = `data:image/*;charset=utf-8;base64,${btoa(svgString)}`;
|
||||||
svgLink.href = svgImageUri;
|
svgLink.href = svgImageUri;
|
||||||
svgLink.innerText = "github-user-contribution.svg";
|
svgLink.innerText = "github-user-contribution.svg";
|
||||||
@@ -237,7 +241,6 @@ const onSubmit = async (userName: string) => {
|
|||||||
colorDots: colorScheme as any,
|
colorDots: colorScheme as any,
|
||||||
colorEmpty: colorScheme[0],
|
colorEmpty: colorScheme[0],
|
||||||
colorSnake: "purple",
|
colorSnake: "purple",
|
||||||
cells,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const grid = userContributionToGrid(cells, colorScheme);
|
const grid = userContributionToGrid(cells, colorScheme);
|
||||||
@@ -246,7 +249,7 @@ const onSubmit = async (userName: string) => {
|
|||||||
|
|
||||||
dispose();
|
dispose();
|
||||||
|
|
||||||
createViewer({ grid0: grid, chain, drawOptions });
|
createViewer({ grid0: grid, chain, cells, drawOptions });
|
||||||
};
|
};
|
||||||
|
|
||||||
const worker = new Worker(
|
const worker = new Worker(
|
||||||
|
|||||||
@@ -4,12 +4,15 @@ import { createSvg } from "@snk/svg-creator";
|
|||||||
import { grid, snake } from "./sample";
|
import { grid, snake } from "./sample";
|
||||||
import { drawOptions } from "./canvas";
|
import { drawOptions } from "./canvas";
|
||||||
import { getPathToPose } from "@snk/solver/getPathToPose";
|
import { getPathToPose } from "@snk/solver/getPathToPose";
|
||||||
|
import type { AnimationOptions } from "@snk/gif-creator";
|
||||||
|
|
||||||
const chain = getBestRoute(grid, snake);
|
const chain = getBestRoute(grid, snake);
|
||||||
chain.push(...getPathToPose(chain.slice(-1)[0], snake)!);
|
chain.push(...getPathToPose(chain.slice(-1)[0], snake)!);
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
const svg = await createSvg(grid, chain, drawOptions, { frameDuration: 200 });
|
const svg = await createSvg(grid, null, chain, drawOptions, {
|
||||||
|
frameDuration: 200,
|
||||||
|
} as AnimationOptions);
|
||||||
|
|
||||||
const container = document.createElement("div");
|
const container = document.createElement("div");
|
||||||
container.innerHTML = svg;
|
container.innerHTML = svg;
|
||||||
|
|||||||
@@ -10,17 +10,17 @@ type Options = {
|
|||||||
sizeCell: number;
|
sizeCell: number;
|
||||||
sizeDot: number;
|
sizeDot: number;
|
||||||
sizeDotBorderRadius: number;
|
sizeDotBorderRadius: number;
|
||||||
cells?: Point[];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const drawGrid = (
|
export const drawGrid = (
|
||||||
ctx: CanvasRenderingContext2D,
|
ctx: CanvasRenderingContext2D,
|
||||||
grid: Grid,
|
grid: Grid,
|
||||||
|
cells: Point[] | null,
|
||||||
o: Options
|
o: Options
|
||||||
) => {
|
) => {
|
||||||
for (let x = grid.width; x--; )
|
for (let x = grid.width; x--; )
|
||||||
for (let y = grid.height; y--; ) {
|
for (let y = grid.height; y--; ) {
|
||||||
if (!o.cells || o.cells.some((c) => c.x === x && c.y === y)) {
|
if (!cells || cells.some((c) => c.x === x && c.y === y)) {
|
||||||
const c = getColor(grid, x, y);
|
const c = getColor(grid, x, y);
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const color = !c ? o.colorEmpty : o.colorDots[c];
|
const color = !c ? o.colorEmpty : o.colorDots[c];
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { drawGrid } from "./drawGrid";
|
import { drawGrid } from "./drawGrid";
|
||||||
import { drawSnake, drawSnakeLerp } from "./drawSnake";
|
import { drawSnake, drawSnakeLerp } from "./drawSnake";
|
||||||
import type { Grid, Color } from "@snk/types/grid";
|
import type { Grid, Color } from "@snk/types/grid";
|
||||||
import type { Point } from "@snk/types/point";
|
|
||||||
import type { Snake } from "@snk/types/snake";
|
import type { Snake } from "@snk/types/snake";
|
||||||
|
import type { Point } from "@snk/types/point";
|
||||||
|
|
||||||
export type Options = {
|
export type Options = {
|
||||||
colorDots: Record<Color, string>;
|
colorDots: Record<Color, string>;
|
||||||
@@ -12,7 +12,6 @@ export type Options = {
|
|||||||
sizeCell: number;
|
sizeCell: number;
|
||||||
sizeDot: number;
|
sizeDot: number;
|
||||||
sizeDotBorderRadius: number;
|
sizeDotBorderRadius: number;
|
||||||
cells?: Point[];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const drawStack = (
|
export const drawStack = (
|
||||||
@@ -37,6 +36,7 @@ export const drawStack = (
|
|||||||
export const drawWorld = (
|
export const drawWorld = (
|
||||||
ctx: CanvasRenderingContext2D,
|
ctx: CanvasRenderingContext2D,
|
||||||
grid: Grid,
|
grid: Grid,
|
||||||
|
cells: Point[] | null,
|
||||||
snake: Snake,
|
snake: Snake,
|
||||||
stack: Color[],
|
stack: Color[],
|
||||||
o: Options
|
o: Options
|
||||||
@@ -44,7 +44,7 @@ export const drawWorld = (
|
|||||||
ctx.save();
|
ctx.save();
|
||||||
|
|
||||||
ctx.translate(1 * o.sizeCell, 2 * o.sizeCell);
|
ctx.translate(1 * o.sizeCell, 2 * o.sizeCell);
|
||||||
drawGrid(ctx, grid, o);
|
drawGrid(ctx, grid, cells, o);
|
||||||
drawSnake(ctx, snake, o);
|
drawSnake(ctx, snake, o);
|
||||||
|
|
||||||
ctx.restore();
|
ctx.restore();
|
||||||
@@ -68,6 +68,7 @@ export const drawWorld = (
|
|||||||
export const drawLerpWorld = (
|
export const drawLerpWorld = (
|
||||||
ctx: CanvasRenderingContext2D,
|
ctx: CanvasRenderingContext2D,
|
||||||
grid: Grid,
|
grid: Grid,
|
||||||
|
cells: Point[] | null,
|
||||||
snake0: Snake,
|
snake0: Snake,
|
||||||
snake1: Snake,
|
snake1: Snake,
|
||||||
stack: Color[],
|
stack: Color[],
|
||||||
@@ -77,7 +78,7 @@ export const drawLerpWorld = (
|
|||||||
ctx.save();
|
ctx.save();
|
||||||
|
|
||||||
ctx.translate(1 * o.sizeCell, 2 * o.sizeCell);
|
ctx.translate(1 * o.sizeCell, 2 * o.sizeCell);
|
||||||
drawGrid(ctx, grid, o);
|
drawGrid(ctx, grid, cells, o);
|
||||||
drawSnakeLerp(ctx, snake0, snake1, k, o);
|
drawSnakeLerp(ctx, snake0, snake1, k, o);
|
||||||
|
|
||||||
ctx.translate(0, (grid.height + 2) * o.sizeCell);
|
ctx.translate(0, (grid.height + 2) * o.sizeCell);
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import * as fs from "fs";
|
|||||||
import { performance } from "perf_hooks";
|
import { performance } from "perf_hooks";
|
||||||
import { createSnakeFromCells } from "@snk/types/snake";
|
import { createSnakeFromCells } from "@snk/types/snake";
|
||||||
import { realistic as grid } from "@snk/types/__fixtures__/grid";
|
import { realistic as grid } from "@snk/types/__fixtures__/grid";
|
||||||
import { createGif } from "..";
|
import { AnimationOptions, createGif } from "..";
|
||||||
import { getBestRoute } from "@snk/solver/getBestRoute";
|
import { getBestRoute } from "@snk/solver/getBestRoute";
|
||||||
import { getPathToPose } from "@snk/solver/getPathToPose";
|
import { getPathToPose } from "@snk/solver/getPathToPose";
|
||||||
import type { Options as DrawOptions } from "@snk/draw/drawWorld";
|
import type { Options as DrawOptions } from "@snk/draw/drawWorld";
|
||||||
@@ -35,7 +35,7 @@ const drawOptions: DrawOptions = {
|
|||||||
colorSnake: "purple",
|
colorSnake: "purple",
|
||||||
};
|
};
|
||||||
|
|
||||||
const gifOptions = { frameDuration: 100, step: 1 };
|
const animationOptions: AnimationOptions = { frameDuration: 100, step: 1 };
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
for (
|
for (
|
||||||
@@ -50,7 +50,13 @@ const gifOptions = { frameDuration: 100, step: 1 };
|
|||||||
const chainL = chain.slice(0, length);
|
const chainL = chain.slice(0, length);
|
||||||
for (let k = 0; k < 10 && (Date.now() - start < 10 * 1000 || k < 2); k++) {
|
for (let k = 0; k < 10 && (Date.now() - start < 10 * 1000 || k < 2); k++) {
|
||||||
const s = performance.now();
|
const s = performance.now();
|
||||||
buffer = await createGif(grid, chainL, drawOptions, gifOptions);
|
buffer = await createGif(
|
||||||
|
grid,
|
||||||
|
null,
|
||||||
|
chainL,
|
||||||
|
drawOptions,
|
||||||
|
animationOptions
|
||||||
|
);
|
||||||
stats.push(performance.now() - s);
|
stats.push(performance.now() - s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import * as fs from "fs";
|
import * as fs from "fs";
|
||||||
import * as path from "path";
|
import * as path from "path";
|
||||||
import { createGif } from "..";
|
import { AnimationOptions, createGif } from "..";
|
||||||
import * as grids from "@snk/types/__fixtures__/grid";
|
import * as grids from "@snk/types/__fixtures__/grid";
|
||||||
import { snake3 as snake } from "@snk/types/__fixtures__/snake";
|
import { snake3 as snake } from "@snk/types/__fixtures__/snake";
|
||||||
import { createSnakeFromCells, nextSnake } from "@snk/types/snake";
|
import { createSnakeFromCells, nextSnake } from "@snk/types/snake";
|
||||||
@@ -20,7 +20,7 @@ const drawOptions: DrawOptions = {
|
|||||||
colorSnake: "purple",
|
colorSnake: "purple",
|
||||||
};
|
};
|
||||||
|
|
||||||
const gifOptions = { frameDuration: 200, step: 1 };
|
const animationOptions: AnimationOptions = { frameDuration: 200, step: 1 };
|
||||||
|
|
||||||
const dir = path.resolve(__dirname, "__snapshots__");
|
const dir = path.resolve(__dirname, "__snapshots__");
|
||||||
|
|
||||||
@@ -40,7 +40,13 @@ for (const key of [
|
|||||||
|
|
||||||
const chain = [snake, ...getBestRoute(grid, snake)!];
|
const chain = [snake, ...getBestRoute(grid, snake)!];
|
||||||
|
|
||||||
const gif = await createGif(grid, chain, drawOptions, gifOptions);
|
const gif = await createGif(
|
||||||
|
grid,
|
||||||
|
null,
|
||||||
|
chain,
|
||||||
|
drawOptions,
|
||||||
|
animationOptions
|
||||||
|
);
|
||||||
|
|
||||||
expect(gif).toBeDefined();
|
expect(gif).toBeDefined();
|
||||||
|
|
||||||
@@ -64,7 +70,7 @@ it(`should generate swipper`, async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const gif = await createGif(grid, chain, drawOptions, gifOptions);
|
const gif = await createGif(grid, null, chain, drawOptions, animationOptions);
|
||||||
|
|
||||||
expect(gif).toBeDefined();
|
expect(gif).toBeDefined();
|
||||||
|
|
||||||
|
|||||||
@@ -5,10 +5,11 @@ import { createCanvas } from "canvas";
|
|||||||
import { Grid, copyGrid, Color } from "@snk/types/grid";
|
import { Grid, copyGrid, Color } from "@snk/types/grid";
|
||||||
import { Snake } from "@snk/types/snake";
|
import { Snake } from "@snk/types/snake";
|
||||||
import {
|
import {
|
||||||
Options,
|
Options as DrawOptions,
|
||||||
drawLerpWorld,
|
drawLerpWorld,
|
||||||
getCanvasWorldSize,
|
getCanvasWorldSize,
|
||||||
} from "@snk/draw/drawWorld";
|
} from "@snk/draw/drawWorld";
|
||||||
|
import type { Point } from "@snk/types/point";
|
||||||
import { step } from "@snk/solver/step";
|
import { step } from "@snk/solver/step";
|
||||||
import tmp from "tmp";
|
import tmp from "tmp";
|
||||||
import gifsicle from "gifsicle";
|
import gifsicle from "gifsicle";
|
||||||
@@ -29,11 +30,14 @@ const withTmpDir = async <T>(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type AnimationOptions = { frameDuration: number; step: number };
|
||||||
|
|
||||||
export const createGif = async (
|
export const createGif = async (
|
||||||
grid0: Grid,
|
grid0: Grid,
|
||||||
|
cells: Point[] | null,
|
||||||
chain: Snake[],
|
chain: Snake[],
|
||||||
drawOptions: Options,
|
drawOptions: DrawOptions,
|
||||||
gifOptions: { frameDuration: number; step: number }
|
animationOptions: AnimationOptions
|
||||||
) =>
|
) =>
|
||||||
withTmpDir(async (dir) => {
|
withTmpDir(async (dir) => {
|
||||||
const { width, height } = getCanvasWorldSize(grid0, drawOptions);
|
const { width, height } = getCanvasWorldSize(grid0, drawOptions);
|
||||||
@@ -46,7 +50,7 @@ export const createGif = async (
|
|||||||
|
|
||||||
const encoder = new GIFEncoder(width, height, "neuquant", true);
|
const encoder = new GIFEncoder(width, height, "neuquant", true);
|
||||||
encoder.setRepeat(0);
|
encoder.setRepeat(0);
|
||||||
encoder.setDelay(gifOptions.frameDuration);
|
encoder.setDelay(animationOptions.frameDuration);
|
||||||
encoder.start();
|
encoder.start();
|
||||||
|
|
||||||
for (let i = 0; i < chain.length; i += 1) {
|
for (let i = 0; i < chain.length; i += 1) {
|
||||||
@@ -54,17 +58,18 @@ export const createGif = async (
|
|||||||
const snake1 = chain[Math.min(chain.length - 1, i + 1)];
|
const snake1 = chain[Math.min(chain.length - 1, i + 1)];
|
||||||
step(grid, stack, snake0);
|
step(grid, stack, snake0);
|
||||||
|
|
||||||
for (let k = 0; k < gifOptions.step; k++) {
|
for (let k = 0; k < animationOptions.step; k++) {
|
||||||
ctx.clearRect(0, 0, width, height);
|
ctx.clearRect(0, 0, width, height);
|
||||||
ctx.fillStyle = "#fff";
|
ctx.fillStyle = "#fff";
|
||||||
ctx.fillRect(0, 0, width, height);
|
ctx.fillRect(0, 0, width, height);
|
||||||
drawLerpWorld(
|
drawLerpWorld(
|
||||||
ctx,
|
ctx,
|
||||||
grid,
|
grid,
|
||||||
|
cells,
|
||||||
snake0,
|
snake0,
|
||||||
snake1,
|
snake1,
|
||||||
stack,
|
stack,
|
||||||
k / gifOptions.step,
|
k / animationOptions.step,
|
||||||
drawOptions
|
drawOptions
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
import * as fs from "fs";
|
import * as fs from "fs";
|
||||||
import * as path from "path";
|
import * as path from "path";
|
||||||
import { createSvg, Options } from "..";
|
import { createSvg, DrawOptions as DrawOptions } from "..";
|
||||||
import * as grids from "@snk/types/__fixtures__/grid";
|
import * as grids from "@snk/types/__fixtures__/grid";
|
||||||
import { snake3 as snake } from "@snk/types/__fixtures__/snake";
|
import { snake3 as snake } from "@snk/types/__fixtures__/snake";
|
||||||
import { getBestRoute } from "@snk/solver/getBestRoute";
|
import { getBestRoute } from "@snk/solver/getBestRoute";
|
||||||
|
import { AnimationOptions } from "@snk/gif-creator";
|
||||||
|
|
||||||
const drawOptions: Options = {
|
const drawOptions: DrawOptions = {
|
||||||
sizeDotBorderRadius: 2,
|
sizeDotBorderRadius: 2,
|
||||||
sizeCell: 16,
|
sizeCell: 16,
|
||||||
sizeDot: 12,
|
sizeDot: 12,
|
||||||
@@ -19,7 +20,7 @@ const drawOptions: Options = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const gifOptions = { frameDuration: 100, step: 1 };
|
const animationOptions: AnimationOptions = { frameDuration: 100, step: 1 };
|
||||||
|
|
||||||
const dir = path.resolve(__dirname, "__snapshots__");
|
const dir = path.resolve(__dirname, "__snapshots__");
|
||||||
|
|
||||||
@@ -31,7 +32,13 @@ for (const [key, grid] of Object.entries(grids))
|
|||||||
it(`should generate ${key} svg`, async () => {
|
it(`should generate ${key} svg`, async () => {
|
||||||
const chain = [snake, ...getBestRoute(grid, snake)!];
|
const chain = [snake, ...getBestRoute(grid, snake)!];
|
||||||
|
|
||||||
const svg = await createSvg(grid, chain, drawOptions, gifOptions);
|
const svg = await createSvg(
|
||||||
|
grid,
|
||||||
|
null,
|
||||||
|
chain,
|
||||||
|
drawOptions,
|
||||||
|
animationOptions
|
||||||
|
);
|
||||||
|
|
||||||
expect(svg).toBeDefined();
|
expect(svg).toBeDefined();
|
||||||
|
|
||||||
|
|||||||
@@ -14,8 +14,9 @@ import { createGrid } from "./grid";
|
|||||||
import { createStack } from "./stack";
|
import { createStack } from "./stack";
|
||||||
import { h } from "./utils";
|
import { h } from "./utils";
|
||||||
import * as csso from "csso";
|
import * as csso from "csso";
|
||||||
|
import { AnimationOptions } from "@snk/gif-creator";
|
||||||
|
|
||||||
export type Options = {
|
export type DrawOptions = {
|
||||||
colorDots: Record<Color, string>;
|
colorDots: Record<Color, string>;
|
||||||
colorEmpty: string;
|
colorEmpty: string;
|
||||||
colorDotBorder: string;
|
colorDotBorder: string;
|
||||||
@@ -23,7 +24,6 @@ export type Options = {
|
|||||||
sizeCell: number;
|
sizeCell: number;
|
||||||
sizeDot: number;
|
sizeDot: number;
|
||||||
sizeDotBorderRadius: number;
|
sizeDotBorderRadius: number;
|
||||||
cells?: Point[];
|
|
||||||
dark?: {
|
dark?: {
|
||||||
colorDots: Record<Color, string>;
|
colorDots: Record<Color, string>;
|
||||||
colorEmpty: string;
|
colorEmpty: string;
|
||||||
@@ -40,12 +40,12 @@ const getCellsFromGrid = ({ width, height }: Grid) =>
|
|||||||
const createLivingCells = (
|
const createLivingCells = (
|
||||||
grid0: Grid,
|
grid0: Grid,
|
||||||
chain: Snake[],
|
chain: Snake[],
|
||||||
drawOptions: Options
|
cells: Point[] | null
|
||||||
) => {
|
) => {
|
||||||
const cells: (Point & {
|
const livingCells: (Point & {
|
||||||
t: number | null;
|
t: number | null;
|
||||||
color: Color | Empty;
|
color: Color | Empty;
|
||||||
})[] = (drawOptions.cells ?? getCellsFromGrid(grid0)).map(({ x, y }) => ({
|
})[] = (cells ?? getCellsFromGrid(grid0)).map(({ x, y }) => ({
|
||||||
x,
|
x,
|
||||||
y,
|
y,
|
||||||
t: null,
|
t: null,
|
||||||
@@ -60,31 +60,32 @@ const createLivingCells = (
|
|||||||
|
|
||||||
if (isInside(grid, x, y) && !isEmpty(getColor(grid, x, y))) {
|
if (isInside(grid, x, y) && !isEmpty(getColor(grid, x, y))) {
|
||||||
setColorEmpty(grid, x, y);
|
setColorEmpty(grid, x, y);
|
||||||
const cell = cells.find((c) => c.x === x && c.y === y)!;
|
const cell = livingCells.find((c) => c.x === x && c.y === y)!;
|
||||||
cell.t = i / chain.length;
|
cell.t = i / chain.length;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return cells;
|
return livingCells;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const createSvg = (
|
export const createSvg = (
|
||||||
grid: Grid,
|
grid: Grid,
|
||||||
|
cells: Point[] | null,
|
||||||
chain: Snake[],
|
chain: Snake[],
|
||||||
drawOptions: Options,
|
drawOptions: DrawOptions,
|
||||||
gifOptions: { frameDuration: number }
|
animationOptions: Pick<AnimationOptions, "frameDuration">
|
||||||
) => {
|
) => {
|
||||||
const width = (grid.width + 2) * drawOptions.sizeCell;
|
const width = (grid.width + 2) * drawOptions.sizeCell;
|
||||||
const height = (grid.height + 5) * drawOptions.sizeCell;
|
const height = (grid.height + 5) * drawOptions.sizeCell;
|
||||||
|
|
||||||
const duration = gifOptions.frameDuration * chain.length;
|
const duration = animationOptions.frameDuration * chain.length;
|
||||||
|
|
||||||
const cells = createLivingCells(grid, chain, drawOptions);
|
const livingCells = createLivingCells(grid, chain, cells);
|
||||||
|
|
||||||
const elements = [
|
const elements = [
|
||||||
createGrid(cells, drawOptions, duration),
|
createGrid(livingCells, drawOptions, duration),
|
||||||
createStack(
|
createStack(
|
||||||
cells,
|
livingCells,
|
||||||
drawOptions,
|
drawOptions,
|
||||||
grid.width * drawOptions.sizeCell,
|
grid.width * drawOptions.sizeCell,
|
||||||
(grid.height + 2) * drawOptions.sizeCell,
|
(grid.height + 2) * drawOptions.sizeCell,
|
||||||
@@ -134,7 +135,7 @@ export const createSvg = (
|
|||||||
const optimizeCss = (css: string) => csso.minify(css).css;
|
const optimizeCss = (css: string) => csso.minify(css).css;
|
||||||
const optimizeSvg = (svg: string) => svg;
|
const optimizeSvg = (svg: string) => svg;
|
||||||
|
|
||||||
const generateColorVar = (drawOptions: Options) =>
|
const generateColorVar = (drawOptions: DrawOptions) =>
|
||||||
`
|
`
|
||||||
:root {
|
:root {
|
||||||
--cb: ${drawOptions.colorDotBorder};
|
--cb: ${drawOptions.colorDotBorder};
|
||||||
|
|||||||
Reference in New Issue
Block a user