Thursday, April 20, 2017

programmatically generating svg files in bulk via javascript / p5.js

I'm tasked with making a series of graphic files (representing various cars' scores in a way that can be embedded on external sites).

We don't know exactly what size the sites will want, so SVG has been a good choice.

We have up to a hundred to generate, so that's an argument for doing things programmatically, rather than in Sketch or Illustrator. Plus I'm a little lazy about learning to new things and neither program jelled immediately for me in the past.

Today I Learned: p5.js has a completely fine SVG implementation!  You'll want to grab a matching set of p5.js and p5.svg.js from the releases page, then something like this will work:

<!doctype html>
<html>
<head>
<title>fun with p5js to svg</title>
<script src="p5.js"></script>
<script src="p5.svg.js"></script>
</head>
<body>
<script>
function setup() {
    createCanvas(600, 200, SVG); // Create SVG Canvas
    strokeWeight(2);
    stroke('#ED225D');
}

function draw() {
    var x = frameCount / 100;
    var y = sin(x * PI * 2);
    line(x * width, height * 0.5,
         x * width, y * height / 2 + height * 0.5);
    if(round(frameCount) % 10 === 0){
        var name = "wave"+frameCount;
        save(name);
    }
    
    if (frameCount > 100) {
        noLoop();
    }
}
</script>
</body>
</html>

You can see it in action here BUT - it will try to autodownload 10 SVG files to your system.

Anyway, I looked harder for the p5.js solution when I realized the SVG.js I looked at previously seemed to have weaksauce support for arcs, which were kind of important to what I was aiming for.

FOLLOWUP NOTES:
Use clear(); instead of background(); if you want to preserve the background transparency on multiple colors. (Kind of runs up how Processing is a generally more about "destroy things every frame and redraw" than traditional SVG... this might be an issue with animations etc)

If you want to display an external SVG (especially if you're going to save this as an SVG) you have to use loadSVG() (in the preload() of course) rather than loadImage(); - otherwise you get a horrible png conversion.


PREVIOUSLY:
Before I found p5.js could do the task, I wrote this...

5 years ago (yeesh) I wrote about using Raphael.js to do some fun SVG animations, but right now I think SVG.js seems like a better bet.

Combining its basic example code with this advice about saving SVGs I came up with the following:
<!DOCTYPE html>
<html>
<head>
  <title>SVG.js</title>
<script src="svg.js"></script>
</head>
<body>
  <div id="drawing"></div>
<script>
// initialize SVG.js
var draw = SVG('drawing')
// draw pink square
draw.rect(100, 100).move(100, 50).fill('#f06')

var a = document.createElement('a');

a.download = 'mySvg.svg';
a.type = 'image/svg+xml';
var blob = new Blob([draw.svg()], {"type": "image/svg+xml"});
a.href = (window.URL || webkitURL).createObjectURL(blob);
a.click();
</script>
</body>
</html>

I think that should scale and fit in a simple loop without too much hassle.

Sunday, April 16, 2017

from "headcrash"

"I mean." Uberman cleared his throat, adjusted his necktie, and began delivering his morning whine, which is clearly what he'd been intending to do all along. "This is, what? The third network outage this year?"

I stopped. "We're having some problems porting your database to our server, sir." I edged one step closer to the exit.

"I mean," Uberman scowled, "if I can't depend on your network, I'm screwed. Just totally screwed, you know?"

Then how come you're not smiling? is what I thought, but "We'll have it back up as soon as possible," is what I said.

"I mean," Uberman whacked his PC with his newspaper again, "we never had problems like this before MDE acquired us. Dammit, our old Applied Photonics network never crashed! Not once!"

"So I've heard." And heard, and heard, and heard! And if you gave me just sixteen users in a one-floor office, I could make this network look pretty good, too.

--Bruce Bethke, "Headcrash", kind of a no-account cyberpunk-y book from the mid-90s... the technobabble is pretty clumsy, but for some reason this passage has stuck with me for 20 years so I thought I'd post it - from time to time, its reminder that little toy systems can get away with things that projects you want to scale can't is useful.

Friday, April 14, 2017

debuggin'

frontend debugging 101

what's easy to do with your toolkit and how it influences your ui

I woke up this morning thinking about Apartmenter. It seemed natural to make it a canvas app, mostly because I was thinking of the funky-shaped walls (like that bay window) of the apartment as a bunch of arbitrary lines, and arbitrary lines are easy to draw in p5.js and more difficult in, say, html5/CSS.

But you know, I think a html5 "draggable lines" (skinny rectangles with a border, most likely) might have produced a better UI, especially for wall layout. My 4am implementation was pretty simplistic, I treated each room as a grid (top left corner 0,0) and each walls as a series of 2 x,y coordinates
rooms : {
  bottomroom:{
    offset: [120,492],
 walls:[
   [0,0,0,176],
    [0,0,115.5,0],
         [115.5,0,115.5,92],
    [115.5,92,150,92],
    [150,92,150,176],
    [150,176,0,176],

    //top door
    [20,0,40,10],

            //closet
    [150,176,176,176],
    [176,176,176,134],
    [176,134,150,134],
    //closet door
    [150,134,140,144],
    [140,144,148,152]
 ]
},
[...]
}

(FWIW, I didn't group each wall as a pair of coordinates [[x1,y1],[x2,y2]] or better yet as a map {"start":{"x":x1,"y":y1},
"end":{"x":x2,"y":y2}} because of some minor typing convenience at the time. )

The thing is, when it came time to update the rooms with more refined measurements (we didn't do a great job with some of the the door placement, for example) this was a pain in the butt, I had to mentally put every wall back on that grid and figure out its endpoints from 0,0. 


If I had treated each wall as a draggable line of a fixed length, as I could have here, and surely WOULD have if I used an html5/css/div approach, life would have been easier, because it maps better to the physical nature of measuring a room with a tape measure.  The only challenge would be the bay window, since I don't easily know the angle to put the window at, but that's pretty easy to figure out with a little math, or trial and error if it came to it.

Counterpoint: the corner-based system I used was a bit nice in how the last x,y corresponded to the first x,y of the next wall, a feature a center-and-length system wouldn't have. Still, I think I could have made things "close enough".


The final version of my program got more sophisticated in drawing, for example, the backs and sides of couches, so they had a clearer orientation and looked different than a table of the same size. I wonder if I had tried a div-based approach if I would have tried to get fancy with CSS :before and :after stuff for such details, or maybe just glommed on some child divs.

Of course I would have had to have gone to stackoverflow for suggestions on movable/draggable divs... JqueryUI offered a fairly clean API for it, and there was this one non-jQuery approach that at first glance looks a little hacky but I haven't studied it deeply. 


Ah well. I don't have any plans to advance this beyond the functional-but-useful-for-me prototype stage, especially now that the layout for our place has been decided with the app's help. If I decided to use it again, I guess I could add a "corner and length" based approach to the canvas code without redoing it all as draggable divs...

Thursday, April 13, 2017

2 recent projects

Two little projects I've worked on lately....

One was my company's April Fool's riff. The idea was a continuation of a finding a car is a bit like romance theme (as best exemplified by last year's Tinder-parody VINder where you could swipe to find the car you'd love.) This year, the idea was a messenger-like chat program to talk directly with the auto - or rather, allowing cars to find the driver they'd love.

I came up with an early rough UI prototype you can play with here- it had a few interesting bits - I think I did a good job with the "hopping dots" as a pure CSS animation. The window scrolling is pretty smart too... I realized that the "other person is talking" always has to occur beneath everything that has happened.  Also I used the trick outlined here to embed a horn sound directly into the page, without needing an external file. We ended up not going with that, but it's a clever idea to know about.

The other project I started in a bout of insomnia, caused in part by wondering if am my girlfriend's and my stuff would fit in the new medium-small apartment we're moving in to together.

I found a few so-so apps for iPad, for sketching out the apartment layout and then putting furniture in. The most attractive was one called Tiny Furniture - it had a great look, was fun to use and was even  easy to sketch out walls, but had some fatal flaws, in that "pinch to resize" was always enabled, so you couldn't lock down the size of a piece of furniture. Also it didn't really have the concept of making a "library" of furniture. I think a usable program would make it both easy to set up the walls like the space you're in and considering, as well as put up a host of pieces you own or might want to buy, and then you can freely drag those around.

So, you can see the first draft of what I made here: stuff.alienbill.com/apart/apartmenter/. (the final version made some minor improvements and allowed saving and loading, but you get the idea) It's a p5.js app using the html5 canvas. It's definitely a rough MVP (Minimal Viable Product) / Proof of Concept but it actually was enough for us to play with layouts and find the one we wanted.

I made a simple form to let the user put in the width, height, and identifying name of a piece, which then gets jammed into the JSON. I made the JSON visible so it can be edited directly, and pushed back into the display. (This lets me also put in irregularly shaped pieces, like the oval tables or the L-shaped couch, without having to build a UI for every thing the program knows how to draw.)

(I've built a few UIs built on saving big blobs of JSON like that, often as regular form data. It's not a bad hack, actually)

The thing I most punted putting in room layout data. That's an interesting UI/UX challenge to thing about - how do you most easily let people (who are probably crawling around on the floor wielding tape measures) put in wall info that is both precisely measured and carefully placed? Do you lock a wall to the corner and then let them adjust the measurement? Do you let them enter a wall of a fixed length and then drag it around? or do you treat it like drawing a straight line in a paint program, but show the current length 'til the user gets it right? Combine with other issues like "walls have widths that probably aren't being measured") and it gets tricky!

As a further hack, I used the same code for a simple "will this dresser fit in our triangular shaped cubbyhole closet" problem - http://stuff.alienbill.com/closeted/ - in this case what was an overhead view is now a side cutaway for the closet and various drawers. (Also in apartmenter, a punt of one inch = one pixel worked well, but here one inch = ten pixels seemed more appropriate)

Anyway, it's nice when a homebrew program like this proves to be so useful in the physical world!


Wednesday, April 5, 2017

simple tool for running a regex on a bunch of lines

I used to be more reliant on my text editor's macro abilities...

I realized in some cases it would be easier to use regular expressions so I made a tool to apply the same reg ex to a bunch of lines of text: regexcellent

You can see some similar tools at http://tools.kirk.is. Most of them are really old and perl cgi based. The one I use most often is tabtransform, that takes the tab delimited data I copy and paste from iTunes and puts it in a template for my monthly music playlist rundowns (I dig up the youtube URLs for each video and slap 'em in the links the script makes)