Just before Christmas I decided to have a play about with SVG on Codepen. It got quite a lot of attention and I was asked to write a post detailing the process; here is that post.
This idea was born because I needed a way to generate isometric backgrounds on-the-fly with a set colour palette. I decided the best way to do it would be to use a formula that would write some SVG code and apply it to the background of an element. The problem was, I’d never used SVG before and I had no idea what I was doing.
I decided to start small and get the basics down first. If I could get something simple generated in SVG first then I could move onto writing the formula that would generate my shapes. I created a random polka dot generator that was surprisingly simple.
I’ve outlined a - simplified - breakdown of that code below.
var width = (dotSize + dotPadding) * dotsWide,
height = (dotSize + dotPadding) * dotsHigh,
radius = dotSize / 2,
background =
"<svg xmlns='http://www.w3.org/2000/svg' width='" +
width +
"' height='" +
height +
"'>",
color = "#09c",
x,
y;
First I define the variables I’m going to use and generate the opening tag for the SVG (assigned to the background variable).
for (x = radius; x < width; x += dotSize + dotPadding) {
for (y = radius; y < height; y += dotSize + dotPadding) {
background +=
"<circle fill='" +
color +
"' cx='" +
x +
"' cy='" +
y +
"' r='" +
radius +
"'/>";
}
}
Then I loop through each circle/dot in the image and append the SVG code to generate it to the background variable.
background += "</svg>";
Once each dot has been added, we close the SVG tag.
var b64 = "data:image/svg+xml;base64," + window.btoa(background),
url = 'url("' + b64 + '")';
$("html").css("backgroundImage", url);
Finally I base64 encode the image before applying it to the background as a Data URI.
The polka dot demo proved to me that I could do this. All I had to do now was write the part that generated my isometric triangles. There’s a few ways to do this but I found this way to be the simplest.
My plan was to generate this bow-tie shape and fill it with a random colour, chosen from a pre-defined array. I would then repeat this shape so it tessellates. The problem I encountered with this approach is that they didn’t stack correctly, and I had with a line of diamond-shaped gaps.
for (i = 0; i <= settings.trianglesWide; i += 1) {
for (j = 0; j <= settings.trianglesHigh; j += 1) {
v = i * settings.triangleSize * settings.skew;
w = j * settings.triangleSize;
x = v + settings.triangleSize * settings.skew;
y = w + settings.triangleSize;
a = v + "," + w;
b = x + "," + w;
c = (v + x) / 2 + "," + (w + y) / 2;
d = v + "," + y;
e = x + "," + y;
background +=
"<polygon fill='" +
getColor() +
"' fill-opacity='" +
settings.opacity +
"' points='" +
a +
" " +
c +
" " +
d +
" " +
"' />";
background +=
"<polygon fill='" +
getColor() +
"' fill-opacity='" +
settings.opacity +
"' points='" +
b +
" " +
c +
" " +
e +
" " +
"' />";
}
}
Gives you…
As you can see, the bow-ties don’t line up quite right but this is fixable. What we need to do is offset every second row by moving it up and along by 50%. I decided to utilise the modulo operation (j % 1)
to differentiate between even and odd rows. This operation will return a 0 when the number is even and a 1 when it’s odd.
for (i = -1; i <= trianglesWide; i += 1) {
for (j = -0.5; j <= trianglesHigh; j += 0.5) {
v = (i + (j % 1)) * triangleSize * skew;
w = j * triangleSize;
x = v + triangleSize * skew;
y = w + triangleSize;
a = v + "," + w;
b = x + "," + w;
c = (v + x) / 2 + "," + (w + y) / 2;
d = v + "," + y;
e = x + "," + y;
background +=
"<polygon fill='" +
getColor() +
"' fill-opacity='" +
opacity +
"' points='" +
a +
" " +
c +
" " +
d +
" " +
"' />";
background +=
"<polygon fill='" +
getColor() +
"' fill-opacity='" +
opacity +
"' points='" +
b +
" " +
c +
" " +
e +
" " +
"' />";
}
}
Adding this in allows us to offset the v
coordinate by 1 on every second row which pushes that row along to the correct point.
You might notice that instead of starting the for loops at 0 I start them at −1 and −0. 5 respectively. This is to make sure the pattern starts outside the bounding box so we don’t get jagged edges.
Another big part of what I wanted to do here was to use random colours from a selected palette. To do this I wrote a simple getColor()
function.
var colors = ["red", "blue", "green"],
getColor = function() {
var hex = colors[Math.floor(Math.random() * colors.length)];
return hex;
};
This shouldn’t need too much of an explanation, it returns a random entry from the colours array when it’s called.
Whilst this is not intended to be a jQuery plugin, I wrote it in that manner to allow me to generate several different backgrounds. Have a play about with the settings at the top of the page or check out the demo on Codepen to see just how versatile this can be.
Comments
(Powered by webmentions)Start the Conversation