Learning SVG

This is not something like a book that helps you learn SVG; rather, it’s more like a notebook I keep to myself while I’m learning SVG-and I’m green, so there, that’s cleared up, I hope.

Basic Shapes

First things first, I need some shapes to work on, so I made these (admittedly boring looking) shapes:
star, circle and square

Code for that:

<svg	xmlns="http://www.w3.org/2000/svg"
	xmlns:xlink="http://www.w3.org/1999/xlink"
		width="240" height="90">
	<def>
		<pattern id="checker" patternUnits="userSpaceOnUse"
				x="0" y="0" width="20" height="20">
			<rect x="0" y="0" height="20" width="20" fill="#aaaaaa"/>
			<rect x="0" y="0" height="10" width="10" fill="#999999"/>
			<rect x="10" y="10" height="10" width="10" fill="#999999"/>
		</pattern>
		<g id="obj">
			<path d="M 40.342584,6.7575912 49.849205,26.134167
				71.215132,29.187812 55.724621,44.216837 59.422867,65.480669
				40.342583,55.392542 21.262297,65.480668 24.960545,44.216837
				9.470034,29.18781 30.83596,26.134167 40.342584,6.7575912 z"/>
			<circle cx="110" cy="40" r="30"/>
			<rect x="160" y="15" width="50" height="50"/>
		</g>
	</def>
	<rect x0="0" y0="0" width="100%" height="100%" fill="url(#checker)"/>
	<use xlink:href="#obj" style="fill:green;stroke:none"/>
</svg>

Yay! I have my first hand-made svg file! (Ok, the path data for the star I lifted from an Inkscape output, but still…)

So I learned how to use <path>, <rect> and <circle> tags; while the “pattern” thing is just the checkered background. There are more types of shapes one can define in SVG, but I’ll stick with these for now.

Gradient

Well, flat green is boring. I know, I’ll put a gradient on them there shapes:

Code:

<svg	xmlns="http://www.w3.org/2000/svg"
	xmlns:xlink="http://www.w3.org/1999/xlink"
		width="240" height="90">
	<def>
		<linearGradient id="greenBg" x1="0" y1="0" x2="0" y2="100%">
			<stop offset="0" stop-color="#7d9a94"/>
			<stop offset="1" stop-color="#aab9b4"/>
		</linearGradient>
		<pattern id="checker" patternUnits="userSpaceOnUse"
				x="0" y="0" width="20" height="20">
			<rect x="0" y="0" height="20" width="20" fill="#aaaaaa"/>
			<rect x="0" y="0" height="10" width="10" fill="#999999"/>
			<rect x="10" y="10" height="10" width="10" fill="#999999"/>
		</pattern>
		<g id="obj">
			<path d="M 40.342584,6.7575912 49.849205,26.134167
				71.215132,29.187812 55.724621,44.216837 59.422867,65.480669
				40.342583,55.392542 21.262297,65.480668 24.960545,44.216837
				9.470034,29.18781 30.83596,26.134167 40.342584,6.7575912 z"/>
			<circle cx="110" cy="40" r="30"/>
			<rect x="160" y="15" width="50" height="50"/>
		</g>
	</def>
	<rect x0="0" y0="0" width="100%" height="100%" fill="url(#checker)"/>
	<use xlink:href="#obj" style="fill:url(#greenBg);stroke:none"/>
</svg>

Now instead of the flat, boring green, I have a … flat, boring gradient. Well. Wait, there’s some kind of filter stuff I can do, that oughta spice things up. Hmm.

Filter

It turns out SVG filters is no easy matter. Fun and powerful, though. Let me try some!

What’s the most used (read: abused) graphical effect? Hands down: dropshadow. So dropshadow it is.

I already knew how a dropshadow is made: you take an image, get the alpha channel from it, blur it somewhat, and put it behind the original image. Luckily, there is a <feGaussianBlur> filter tag in SVG, so let’s make a filter from that:

<svg	xmlns="http://www.w3.org/2000/svg"
		xmlns:xlink="http://www.w3.org/1999/xlink"
		width="240" height="100">
	<def>
		<linearGradient id="greenBg" x1="0" y1="0" x2="0" y2="100%">
			<stop offset="0" stop-color="#aab9b4"/>
			<stop offset="1" stop-color="#7d9a94"/>
		</linearGradient>
		<pattern id="checker" patternUnits="userSpaceOnUse"
				x="0" y="0" width="20" height="20">
			<rect x="0" y="0" height="20" width="20" fill="#aaaaaa"/>
			<rect x="0" y="0" height="10" width="10" fill="#999999"/>
			<rect x="10" y="10" height="10" width="10" fill="#999999"/>
		</pattern>
		<g id="obj">
		<path d="M 40.342584,6.7575912 49.849205,26.134167 71.215132,29.187812
			55.724621,44.216837 59.422867,65.480669 40.342583,55.392542
			21.262297,65.480668 24.960545,44.216837 9.470034,29.18781
			30.83596,26.134167 40.342584,6.7575912 z"/>
		<circle cx="113" cy="40" r="30"/>
		<rect x="160" y="15" width="50" height="50"/>
		</g>
		<filter id="dropshadow" x0="-50%" y0="-50%" width="200%" height="200%">
			<feGaussianBlur in="SourceAlpha" stdDeviation="2" result="blur"/>
		</filter>
	</def>

	<rect x0="0" y0="0" width="600" height="600" fill="url(#checker)"/>
	<use xlink:href="#obj" style="fill:url(#greenBg);stroke:none;filter:url(#dropshadow)"/>
</svg>

Easy breezy. The result is, er:

So the filter above does produce the dropshaow, and only the dropshadow. I still need to put the original shapes back in there somehow. I could just draw it again, without any filter this time, so the second copy of the shapes with its exciting gradient sits on top of the shadow. But that means every time I apply the filter on an object, I need to redraw that object again, which is somehow not very satisfying (I’m peculiar, I know). After digging some more on the W3C SVG website, ah! There’s the <feComposite> thingy. Does “Porter-Duff” ring a bell? Anyway.

So the above code is changed into

...
		<filter id="dropshadow" x0="-50%" y0="-50%" width="200%" height="200%">
			<feGaussianBlur in="SourceAlpha" stdDeviation="2"/>
			<feOffset dx="3" dy="4" result="blur" />
			<feComposite in="SourceGraphic" in2="blur" operator="over"/>
		</filter>
...

and the result is more like what I had in mind:

The shadow is also moved slightly to the lower-right, to give the illusion of light coming from top left (the <feOffset> did that).

So far, so good. But anybody can make a black dropshadow, and I want to stand out. I want a red one. I’m not sure what is the generally agreed method of doing that, but the way I manged to do it is flood fill with a color I want (<feFlood flood-color="a color I want"/>), then composite it in the shadow. Basically, it fills the whole area with said color, then copies the alpha values of the shadow to this colored block, so we end up with my choice color, but in the shape of the shadow. Code:

		<filter id="dropshadow" x0="-50%" y0="-50%" width="200%" height="200%">
			<feGaussianBlur in="SourceAlpha" stdDeviation="2"/>
			<feOffset dx="3" dy="4" result="blur" />
			<feFlood flood-color="maroon" />
			<feComposite in2="blur" operator="in" result="colorShadow"/>
			<feComposite in="SourceGraphic" in2="colorShadow" operator="over"/>
		</filter>

the result (when I said “red”, I meant “maroon”. I’m not insane):

Now I saw that it is good. Just the red shadow I wanted. Except it looks a little skimpy. I could make it wider by making the stdDeviation of the Gaussian blur bigger, so the blurring extends further. Currently it’s 2, let’s try, say, 8:

			<feGaussianBlur in="SourceAlpha" stdDeviation="8"/>

Now it becomes:

It is wider, but now it’s skimpy in another way: the shadow is not solid enough. In Photoshop, when doing dropshadows, besides the sigma (the stdDeviation here), there’s also another parameter called “spread”, which dictates how far the shadow extends outwards before it starts fading. In the same vein, I need to make the shapes “fatter” before bluring it, so that the shadows will be more solid for a longer distance. The “enfattening” (is that a word?) is done by <feEnfatten>, I mean, <feMorphology> filter, with the “dilate” operator:

		<filter id="dropshadow" x0="-50%" y0="-50%" width="200%" height="200%">
			<feMorphology in="SourceAlpha" radius="6" operator="dilate"/>
			<feGaussianBlur stdDeviation="2"/>
			<feOffset dx="3" dy="4" result="blur" />
			<feFlood flood-color="maroon" />
			<feComposite in2="blur" operator="in" result="colorShadow"/>
			<feComposite in="SourceGraphic" in2="colorShadow" operator="over"/>
		</filter>

The blurring radius is back to 2 as before, but first we extend the shapes by 6 first. Now look at my spunky, gory red shadow:

It is obviously bad for health, but in name of science, it was worth it. Now I’ll just wrap up my first lesson with a more reasonable looking specimen:

		<filter id="dropshadow" x0="-50%" y0="-50%" width="200%" height="200%">
			<feMorphology in="SourceAlpha" radius="1" operator="dilate"/>
			<feGaussianBlur stdDeviation="3"/>
			<feOffset dx="4" dy="5" result="blur" />
			<feFlood flood-color="#442222" flood-opacity="0.7"/>
			<feComposite in2="blur" operator="in" result="colorShadow"/>
			<feComposite in="SourceGraphic" in2="colorShadow" operator="over"/>
		</filter>

Now I know how to do dropshadows, I’ll call it lesson 1. Well done, me.

Advertisements
  1. Leave a comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: