Generating JavaScript from SVG, an Intro to Code Generation — Part 2

Cycling '74 Engineering
4 min readMay 6, 2021

Hi and welcome back to an introduction to code generation. If you haven’t read the first part of this series, we’re trying to generate JavaScript code that will recreate an SVG drawing. In the last part, we managed to write a parser/generator that could understand any drawing, so long as it was made up entirely of black rectangles.

This, I think you’ll agree, is art

In this part of the series, we’ll add generated code to scale and stretch our image as we resize our Max object. We’re working from the repository at https://github.com/Cycling74/codegen-eng-blog. If you want to pick up where we left off last time, you can checkout the step-2 tag, with something like this:

git checkout tags/step-2

Scaling and Stretching

Let’s get started. Right now, if we start to resize our object in Max, our rectangles will just sit there.

Checking the jspainter documentation, there is a way to tell Max to automatically stretch the drawing. mgraphics.relative_coords = 1; at the beginning of our source file will turn on relative coordinate mode, putting (0, 0) in the center of the canvas and (-1, -1) in the top right (I agree, this is an idiosyncratic coordinate system). So now we’ve got to figure out how to convert the coordinates of the rectangles in our SVG file to jspainter’s relative coordinate system. Luckily, looking back at our SVG file, we see that it includes an explicit viewBox="0 0 177.3 307". So all we have to do is extract this while we walk through the SVG file with htmlparser2 and use it to scale our rectangles. There’s one other change: adding mgraphics.relative_coords = 1 to makePaintFunction.

As you can see, the way we scale each rectangle is a little different than how you might expect, since we’re stretching to a coordinate system that goes from (-1, -1) in the top-left to (1, 1) in the bottom right. Or… did we do that scaling right?

That’s not how it’s supposed to look

That doesn’t look quite right. Ah, right, that’s because I made a mistake: the coordinate system for jspainter actually begins in the bottom left, so (-1, -1) is in the bottom-left and (1, 1) is in the top right. We have to change our scaling code accordingly:

The only bit that’s changed is the y coordinate. With that, we’ve can now resize and see our drawing resize as well.

Aspect Ratios

This is fine so long as we’re happy with a fixed aspect ratio for our drawing. If we want the drawing to scale with the bounds of the object, then we need to incorporate an aspect ratio scaling into our code. The key is that we need to put this logic into the exported code itself. What’s kind of cool about this is that now we’re defining behavior that isn’t present in the original SVG file. First, we add a function to calculate aspect ratio to our generated paint code.

As you can see, this adds a local aspect variable to our paint function. Now, since our rectangle drawing functions are just lists of statements in the paint function, we can make use of this local variable in our rectangle drawing code. We don’t have to pass the aspect variable to the rectangle function or anything like that, we can just use the local aspect variable directly.

Surprisingly that’s all we need to do to get a drawing that will stretch to whatever aspect ratio we want in Max.

Home Stretch

If you want to jump ahead and see all the code we wrote in this section, checkout the step-3 tag:

git checkout tags/step-3

In the last part of the series, we’ll break with our monochromatic streak and see how to add some color to our drawing. Look out for some CSS-parsing action in the exciting conclusion to our code generation intro series!

--

--

Cycling '74 Engineering

We’re the engineers behind Max, the visual programming environment for sound and video. Follow for more programming stories, side projects and rabbit holes.