Allow width and height to be dynamic

This commit is contained in:
arne 2024-07-20 19:15:35 +02:00
commit 49ec5de609

View file

@ -2,32 +2,38 @@ import { line, type Line, group, translate, asSvg, svgDoc, scale, flip } from "@
import { vec2, type Vec2 } from "@thi.ng/vectors" import { vec2, type Vec2 } from "@thi.ng/vectors"
import { $canvas } from "@thi.ng/rdom-canvas"; import { $canvas } from "@thi.ng/rdom-canvas";
import { reactive, sync } from "@thi.ng/rstream"; import { reactive, sync } from "@thi.ng/rstream";
import { $compile, $input } from '@thi.ng/rdom' import { $compile, $input, $inputNum } from '@thi.ng/rdom'
import { cycle, comp, range, iterator, map, mapcat, reverse, zip } from "@thi.ng/transducers" import { cycle, comp, range, iterator, map, mapcat, reverse, zip } from "@thi.ng/transducers"
const cellSize_ = "12" // initial settings
const xs_ = "101110100101100"
const ys_ = "101001111001110000101"
const parsePattern = (pattern: string) => pattern.split('').map(x => Number.parseInt(x, 10)) // available size for a2: 420 * 594
const width_ = 420
const height_ = 594
const cellSize_ = 12
const xSeeds = reactive(xs_).map((pattern) => parsePattern(pattern)) const xSeeds_ = "101110100101100"
const ySeeds = reactive(ys_).map((pattern) => parsePattern(pattern)) const ySeeds_ = "101001111001110000101"
const cellSize = reactive(cellSize_).map(num => { const unit_ = 'mm'
const next = Number.parseInt(num, 10)
return Number.isNaN(next)|| next < 5 ? 5 : next // turn these into reactive values to trigger re-rendering on change
})
const width = reactive(width_)
const height = reactive(height_)
const unit = reactive(unit_)
const size = sync({ src: { width, height } }).map(({ width, height }) => [width, height])
const toNumber = (v: any) => typeof v === 'number' ? v : Number.parseInt(v, 10)
const parsePattern = (pattern: string) => pattern.split('').map(toNumber)
const xSeeds = reactive(xSeeds_).map((pattern) => parsePattern(pattern))
const ySeeds = reactive(ySeeds_).map((pattern) => parsePattern(pattern))
const cellSize = reactive(cellSize_).map(num => Number.isNaN(num) || num < 5 ? 5 : num) // restrict cells to be at least 5 $unit
// const backgroundColor = getComputedStyle(document.documentElement).getPropertyValue('--background-color') // const backgroundColor = getComputedStyle(document.documentElement).getPropertyValue('--background-color')
const primaryColor = getComputedStyle(document.documentElement).getPropertyValue('--primary-color') const primaryColor = getComputedStyle(document.documentElement).getPropertyValue('--primary-color')
const secondaryColor = getComputedStyle(document.documentElement).getPropertyValue('--secondary-color') const secondaryColor = getComputedStyle(document.documentElement).getPropertyValue('--secondary-color')
// available size for a2: 420 * 594
const width = 420
const height = 594
const size = [width, height]
// some explanation for what's happening below: // some explanation for what's happening below:
// //
// - a coord is a position on a single axis // - a coord is a position on a single axis
@ -71,8 +77,19 @@ const generateLines = (maxCoordOnAxis: number, maxCoordPerpendicular: number, se
// now we can put the functions above together based on the current settings and generate a scene to be drawn // now we can put the functions above together based on the current settings and generate a scene to be drawn
const scene = sync({ const scene = sync({
src: { cellSize, xSeeds, ySeeds, } src: {
}).map(({ cellSize, xSeeds, ySeeds }) => { size,
cellSize,
xSeeds,
ySeeds,
}
}).map(({
size,
cellSize,
xSeeds,
ySeeds,
}) => {
const [width, height] = size
const minPadding = cellSize const minPadding = cellSize
// calculate available drawing area // calculate available drawing area
@ -85,15 +102,13 @@ const scene = sync({
const xLines = [...map(l => scale(l, cellSize), generateLines(yCells, xCells, cycle(ySeeds), xLineGen))] const xLines = [...map(l => scale(l, cellSize), generateLines(yCells, xCells, cycle(ySeeds), xLineGen))]
const yLines = [...map(l => scale(l, cellSize), generateLines(xCells, yCells, cycle(xSeeds), yLineGen))] const yLines = [...map(l => scale(l, cellSize), generateLines(xCells, yCells, cycle(xSeeds), yLineGen))]
const scene = translate( return translate(
group( group(
{ __background: primaryColor, stroke: secondaryColor }, { __background: primaryColor, stroke: secondaryColor },
[...yLines, ...xLines] [...yLines, ...xLines]
), ),
[xPadding, yPadding] [xPadding, yPadding]
) )
return scene
}) })
const input = (label: string, attrs: any) => const input = (label: string, attrs: any) =>
@ -106,25 +121,47 @@ $compile(
$canvas(scene, size)], $canvas(scene, size)],
["aside", {}, ["aside", {},
["h2", {}, "Settings"], ["h2", {}, "Settings"],
input("Canvas width:", {
type: "number",
min: "10",
value: width.deref()!,
oninput: $inputNum(width),
}),
input("Canvas height:", {
type: "number",
min: "10",
value: height.deref()!,
oninput: $inputNum(height),
}),
input("Grid size: ", { input("Grid size: ", {
type: "number", type: "number",
min: "5", min: "5",
value: cellSize.deref()!, value: cellSize.deref()!,
oninput: $input(cellSize) oninput: $inputNum(cellSize),
}), }),
input("X Pattern: ", { input("X Pattern: ", {
type: "text", type: "text",
value: xs_, value: xSeeds_,
oninput: $input(xSeeds) oninput: $input(xSeeds)
}), }),
input("Y Pattern: ", { input("Y Pattern: ", {
type: "text", type: "text",
value: ys_, value: ySeeds_,
oninput: $input(ySeeds) oninput: $input(ySeeds)
}), }),
["h2", {}, "SVG Export"], ["h2", {}, "SVG Export"],
["div", {}, ["textarea", { ["div", {}, ["textarea", {
value: scene.map((scene) => asSvg(svgDoc({ viewBox: `0 0 ${size[0]} ${size[1]}` }, scene))), value: sync({
src: {
scene,
size,
unit,
}
}).map(({
scene,
size,
unit
}) => asSvg(svgDoc({ width: `${size[0]}${unit}`, height: `${size[1]}${unit}`, viewBox: `0 0 ${size[0]} ${size[1]}` }, scene))),
cols: 80, cols: 80,
rows: 20 rows: 20
}]]]] }]]]]