build out svg adapter, viewBox isn't working yet
This commit is contained in:
parent
e72b9f91ca
commit
1085c7ae44
111
build/ludus.mjs
111
build/ludus.mjs
|
@ -4,7 +4,10 @@ const mod = await init()
|
||||||
|
|
||||||
let result = null
|
let result = null
|
||||||
|
|
||||||
|
let code = null
|
||||||
|
|
||||||
export function run (source) {
|
export function run (source) {
|
||||||
|
code = source
|
||||||
const output = mod.ludus(source).value
|
const output = mod.ludus(source).value
|
||||||
result = JSON.parse(output)
|
result = JSON.parse(output)
|
||||||
return result
|
return result
|
||||||
|
@ -20,10 +23,6 @@ export function turtle_commands () {
|
||||||
return result.io.turtle.data
|
return result.io.turtle.data
|
||||||
}
|
}
|
||||||
|
|
||||||
export function svg () {
|
|
||||||
// TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
const turtle_init = {
|
const turtle_init = {
|
||||||
position: [0, 0],
|
position: [0, 0],
|
||||||
heading: 0,
|
heading: 0,
|
||||||
|
@ -154,7 +153,7 @@ function command_to_state (prev_state, curr_command) {
|
||||||
let color = curr_command.slice(1)
|
let color = curr_command.slice(1)
|
||||||
if (color.lengh = 1) color = color[0]
|
if (color.lengh = 1) color = color[0]
|
||||||
background_color = color
|
background_color = color
|
||||||
return
|
return prev_state
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -211,12 +210,106 @@ function turn_to_rad (heading) {
|
||||||
return heading * 2 * Math.PI
|
return heading * 2 * Math.PI
|
||||||
}
|
}
|
||||||
|
|
||||||
function render_turtle (state, calls) {
|
function turn_to_deg (heading) {
|
||||||
|
return (heading * 360) + 180
|
||||||
|
}
|
||||||
|
|
||||||
|
function svg_render_line (prev, curr) {
|
||||||
|
if (!prev.pendown) return ""
|
||||||
|
if (are_eq(prev.position, curr.position)) return ""
|
||||||
|
const {position: [x1, y1], pencolor, penwidth} = prev
|
||||||
|
const {position: [x2, y2]} = curr
|
||||||
|
const [r, g, b, a] = resolve_color(pencolor)
|
||||||
|
return `
|
||||||
|
<line x1="${x1}" y1="${y1}" x2="${x2}" y2="${y2}" stroke="rgb(${r} ${g} ${b})" stroke-opacity="${a/255}" stroke-width="${penwidth}"/>
|
||||||
|
`
|
||||||
|
}
|
||||||
|
|
||||||
|
function escape_svg (svg) {
|
||||||
|
return svg
|
||||||
|
.replace(/&/g, "&")
|
||||||
|
.replace(/</g, "<")
|
||||||
|
.replace(/>/g, ">")
|
||||||
|
.replace(/"/g, """)
|
||||||
|
.replace(/'/g, "'")
|
||||||
|
}
|
||||||
|
|
||||||
|
function svg_render_path (states) {
|
||||||
|
const path = []
|
||||||
|
for (let i = 1; i < states.length; ++i) {
|
||||||
|
const prev = states[i - 1]
|
||||||
|
const curr = states[i]
|
||||||
|
path.push(svg_render_line(prev, curr))
|
||||||
|
}
|
||||||
|
return path.join("")
|
||||||
|
}
|
||||||
|
|
||||||
|
function svg_render_turtle (state) {
|
||||||
|
if (!state.visible) return ""
|
||||||
|
const [fr, fg, fb, fa] = turtle_color
|
||||||
|
const fill_alpha = fa/255
|
||||||
|
const {heading, pencolor, position: [x, y], pendown, penwidth} = state
|
||||||
|
const origin = [0, turtle_radius]
|
||||||
|
const [x1, y1] = origin
|
||||||
|
const [x2, y2] = rotate(origin, turtle_angle)
|
||||||
|
const [x3, y3] = rotate(origin, -turtle_angle)
|
||||||
|
const [pr, pg, pb, pa] = resolve_color(pencolor)
|
||||||
|
const pen_alpha = pa/255
|
||||||
|
const ink = pendown ? `<line x1="${x1}" y1="${y1}" x2="0" y2="0" stroke="rgb(${pr} ${pg} ${pb})" stroke-opacity="${pen_alpha}" stroke-width="${penwidth}" />` : ""
|
||||||
|
return `
|
||||||
|
<g transform="translate(${x}, ${y})rotate(${turn_to_deg(heading)})">
|
||||||
|
<polygon points="${x1} ${y1} ${x2} ${y2} ${x3} ${y3}" stroke="none" fill="rgb(${fr} ${fg} ${fb})" fill-opacity="${fill_alpha}"/>
|
||||||
|
${ink}
|
||||||
|
</g>
|
||||||
|
`
|
||||||
|
}
|
||||||
|
|
||||||
|
export function svg (commands) {
|
||||||
|
const states = [turtle_init]
|
||||||
|
commands.reduce((prev_state, command) => {
|
||||||
|
const new_state = command_to_state(prev_state, command)
|
||||||
|
states.push(new_state)
|
||||||
|
return new_state
|
||||||
|
}, turtle_init)
|
||||||
|
const {maxX, maxY, minX, minY} = states.reduce((accum, {position: [x, y]}) => {
|
||||||
|
accum.maxX = Math.max(accum.maxX, x)
|
||||||
|
accum.maxY = Math.max(accum.maxY, y)
|
||||||
|
accum.minX = Math.min(accum.minX, x)
|
||||||
|
accum.minY = Math.min(accum.minY, y)
|
||||||
|
return accum
|
||||||
|
|
||||||
|
}, {maxX: 0, maxY: 0, minX: 0, minY: 0})
|
||||||
|
const [r, g, b, a] = resolve_color(background_color)
|
||||||
|
const view_width = maxX - minX
|
||||||
|
const view_height = maxY - minY
|
||||||
|
const margin = Math.max(view_width, view_height) * 0.1
|
||||||
|
const x1 = minX - margin
|
||||||
|
const y1 = minY - margin
|
||||||
|
const x2 = maxX + margin
|
||||||
|
const y2 = maxY + margin
|
||||||
|
const path = svg_render_path(states)
|
||||||
|
const turtle = svg_render_turtle(states[states.length - 1])
|
||||||
|
return `<?xml version="1.0" xmlns="http://www.w3.org/2000/svg" standalone="no"?>
|
||||||
|
<svg version="1.1" style="background-color:rgb(${r} ${g} ${b}); background-opacity: ${a/255}" viewBox="${x1} ${y1} ${x2} ${y2}">
|
||||||
|
|
||||||
|
<g>
|
||||||
|
${path}
|
||||||
|
${turtle}
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<ludus>
|
||||||
|
${escape_svg(code)}
|
||||||
|
</ludus>
|
||||||
|
</svg>
|
||||||
|
`
|
||||||
|
}
|
||||||
|
|
||||||
|
function p5_render_turtle (state, calls) {
|
||||||
if (!state.visible) return
|
if (!state.visible) return
|
||||||
calls.push(["push"])
|
calls.push(["push"])
|
||||||
const [r, g, b, a] = turtle_color
|
const [r, g, b, a] = turtle_color
|
||||||
calls.push(["fill", r, g, b, a])
|
calls.push(["fill", r, g, b, a])
|
||||||
const {heading, pencolor, position: [x, y], pendown} = state
|
const {heading, pencolor, position: [x, y], pendown, penwidth} = state
|
||||||
const origin = [0, turtle_radius]
|
const origin = [0, turtle_radius]
|
||||||
const [x1, y1] = origin
|
const [x1, y1] = origin
|
||||||
const [x2, y2] = rotate(origin, turtle_angle)
|
const [x2, y2] = rotate(origin, turtle_angle)
|
||||||
|
@ -229,6 +322,7 @@ function render_turtle (state, calls) {
|
||||||
calls.push(["vertex", x2, y2])
|
calls.push(["vertex", x2, y2])
|
||||||
calls.push(["vertex", x3, y3])
|
calls.push(["vertex", x3, y3])
|
||||||
calls.push(["endShape"])
|
calls.push(["endShape"])
|
||||||
|
calls.push(["strokeWeight", penwidth])
|
||||||
calls.push(["stroke", ...resolve_color(pencolor)])
|
calls.push(["stroke", ...resolve_color(pencolor)])
|
||||||
if (pendown) calls.push(["line", 0, 0, x1, y1])
|
if (pendown) calls.push(["line", 0, 0, x1, y1])
|
||||||
calls.push(["pop"])
|
calls.push(["pop"])
|
||||||
|
@ -252,6 +346,7 @@ export function p5_calls (commands) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
p5_calls[0] = ["background", ...resolve_color(background_color)]
|
p5_calls[0] = ["background", ...resolve_color(background_color)]
|
||||||
render_turtle(states[states.length - 1], p5_calls)
|
p5_render_turtle(states[states.length - 1], p5_calls)
|
||||||
return p5_calls
|
return p5_calls
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
11
build/svg_test.mjs
Normal file
11
build/svg_test.mjs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
import {run, svg} from "./ludus.mjs"
|
||||||
|
|
||||||
|
const code = `
|
||||||
|
forward! (100)
|
||||||
|
right! (0.25)
|
||||||
|
forward! (100)
|
||||||
|
`
|
||||||
|
|
||||||
|
const result = run(code)
|
||||||
|
|
||||||
|
console.log(svg(result.io.turtle.data))
|
26
build/svg_test.svg
Normal file
26
build/svg_test.svg
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
<?xml version="1.0" standalone="no"?>
|
||||||
|
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" style="background-color:rgb(0 0 0); background-opacity: 0.5" viewBox="-300 -300 900 900">
|
||||||
|
|
||||||
|
<g transform="scale(-1, 1) rotate(180)">
|
||||||
|
|
||||||
|
<line x1="0" y1="0" x2="6.123233995736766e-15" y2="100" stroke="rgb(255 255 255)" stroke-opacity="1" stroke-width="1"/>
|
||||||
|
|
||||||
|
<line x1="6.123233995736766e-15" y1="100" x2="100" y2="100" stroke="rgb(255 255 255)" stroke-opacity="1" stroke-width="1"/>
|
||||||
|
|
||||||
|
|
||||||
|
<g transform="translate(100, 100) rotate(270)">
|
||||||
|
<polygon points="0 20 -13.226237306473037 -15.00222139260919 13.226237306473037 -15.00222139260919" stroke="none" fill="rgb(255 255 255)" fill-opacity="0.5882352941176471"/>
|
||||||
|
<line x1="0" y1="20" x2="0" y2="0" stroke="rgb(255 255 255)" stroke-opacity="1" stroke-width="1" />
|
||||||
|
</g>
|
||||||
|
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<ludus>
|
||||||
|
|
||||||
|
forward! (100)
|
||||||
|
right! (0.25)
|
||||||
|
forward! (100)
|
||||||
|
|
||||||
|
</ludus>
|
||||||
|
</svg>
|
||||||
|
|
After Width: | Height: | Size: 937 B |
18
build/test.svg
Normal file
18
build/test.svg
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
<?xml version="1.0" standalone="no"?>
|
||||||
|
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" style="background-color:navy" viewBox="-100 -100 500 500">
|
||||||
|
|
||||||
|
<rect x="-10.5" y="6.123233995736766e-15" width="300" height="300.2" stroke="white" fill="transparent" stroke-width="1"/>
|
||||||
|
|
||||||
|
<g transform="translate(100, 100) rotate(180) rotate(180)">
|
||||||
|
<polygon points="0 20 -13.2262 -15.0022 13.2262 -15.0022" stroke="none" fill="rgb(150 150 150)" fill-opacity="0.6"/>
|
||||||
|
|
||||||
|
<line x1="0" y1="0" x2="0" y2="20" stroke="white" stroke-width="1"/>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<ludus>
|
||||||
|
& this is some code
|
||||||
|
forward! (100)
|
||||||
|
right! (0.25)
|
||||||
|
</ludus>
|
||||||
|
</svg>
|
||||||
|
|
After Width: | Height: | Size: 620 B |
Loading…
Reference in New Issue
Block a user