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 { $canvas } from "@thi.ng/rdom-canvas";
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"
const cellSize_ = "12"
const xs_ = "101110100101100"
const ys_ = "101001111001110000101"
// initial settings
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 ySeeds = reactive(ys_).map((pattern) => parsePattern(pattern))
const cellSize = reactive(cellSize_).map(num => {
const next = Number.parseInt(num, 10)
return Number.isNaN(next)|| next < 5 ? 5 : next
})
const xSeeds_ = "101110100101100"
const ySeeds_ = "101001111001110000101"
const unit_ = 'mm'
// 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 primaryColor = getComputedStyle(document.documentElement).getPropertyValue('--primary-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:
//
// - 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
const scene = sync({
src: { cellSize, xSeeds, ySeeds, }
}).map(({ cellSize, xSeeds, ySeeds }) => {
src: {
size,
cellSize,
xSeeds,
ySeeds,
}
}).map(({
size,
cellSize,
xSeeds,
ySeeds,
}) => {
const [width, height] = size
const minPadding = cellSize
// 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 yLines = [...map(l => scale(l, cellSize), generateLines(xCells, yCells, cycle(xSeeds), yLineGen))]
const scene = translate(
return translate(
group(
{ __background: primaryColor, stroke: secondaryColor },
[...yLines, ...xLines]
),
[xPadding, yPadding]
)
return scene
})
const input = (label: string, attrs: any) =>
@ -106,25 +121,47 @@ $compile(
$canvas(scene, size)],
["aside", {},
["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: ", {
type: "number",
min: "5",
value: cellSize.deref()!,
oninput: $input(cellSize)
oninput: $inputNum(cellSize),
}),
input("X Pattern: ", {
type: "text",
value: xs_,
value: xSeeds_,
oninput: $input(xSeeds)
}),
input("Y Pattern: ", {
type: "text",
value: ys_,
value: ySeeds_,
oninput: $input(ySeeds)
}),
["h2", {}, "SVG Export"],
["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,
rows: 20
}]]]]