Wednesday 26 October 2016

SVG Filter Primitives for Working with External Images and SVG Fragments - Vanseo Design

SVG Filter Primitives for Working with External Images and SVG Fragments - Vanseo Design


SVG Filter Primitives for Working with External Images and SVG Fragments

Posted: 25 Oct 2016 05:30 AM PDT

There will be times when the effect you want to add requires an additional image beyond the source graphic. Fortunately SVG provides a way to allow us to load external images inside a filter and make them part of the effect.

Last week I started to cover the details of SVG filter primitives as part of a larger series about filter effects. I began with an overview of SVG filters and then walked through the filter element before talking about filter primitives and some details about their input and output.

Today I want to continue with a couple more filter primitives that both involve working with external images directly inside SVG filters. The first feImage allows you to include external images and SVG fragments and the second, feTile, allows you to tile them.v

The feImage Filter Primitive

The feImage filter primitive allows you to refer to an external image or graphic and load it as the result of the primitive. You can refer to an external image or you can reference another SVG fragment.

If you reference an external image (.jpg, .png, or .svg file) the resource is rendered according to the behavior of the <image> element. Otherwise it's rendered according to the behavior of the <use> element.

The primitive takes two attributes, xlink:href and preserveAspectRatio.

1  2  
xlink:href = <iri> // reference to image source  preserveAspectRatio = [defer] <align> [<meetOrSlice>]

I've discussed both of these attributes in an earlier series. xlink:href points to the image and preserveAspectRatio determines whether the aspect ratio of the image should be preserved and if so how.

Since I've covered it before, I'll point you to an earlier post on preserveAspectRatio for details. If you don't specify a value the default is xMidYMid, which centers the image in the filter effects region and preserves its aspect ratio. You can, if you like, offset the image by setting values for x and y.

Here's an example that hopefully illustrates how the feImage filter primitive works. I created two filters that both refer to the same external image of Strawberry Fields in Central Park. The only difference in the two filters is the first preserves the aspect ratio and the second doesn't.

I also created two pairs of identically sized rectangles. In each pair one rectangle will reference a filter and the other is there to show a blue outline for where the rectangle is located.

Finally, notice that I set the filter effects region so that it's the same size as the rectangles (or squares).

1  2  3  4  5  6  7  8  9  10  11  12  13  14  15  16  17  
<svg width="100%" height="220" style="outline: 1px solid red">   <defs>     <filter id="default" x="0" y="0" width="100%" height="100%">       <feImage xlink:href="http://www.vanseodesign.com/blog/wp-content/uploads/2013/09/strawberry-fields.jpg" result="strawberry-fields" />     </filter>       <filter id="preserved" x="0" y="0" width="100%" height="100%">       <feImage xlink:href="http://www.vanseodesign.com/blog/wp-content/uploads/2013/09/strawberry-fields.jpg" result="strawberry-fields"  preserveAspectRatio="none" />     </filter>   </defs>     <rect x="10" y="10" width="100" height="100" filter="url(#default)" />   <rect x="10" y="10" width="100" height="100" fill="none" stroke="#00f" />     <rect x="120" y="10" width="100" height="100" filter="url(#preserved)" />   <rect x="120" y="10" width="100" height="100" fill="none" stroke="#00f" />  </svg>

On the left the aspect ratio of the image is preserved. The longer dimension, in this case the width, fills the space from edge to edge and the other dimension is set to preserve the aspect ratio of the image. Because the image in this example isn't square you can see some empty space above and below.

On the right, the aspect ratio isn't preserved and the image has been stretched vertically to fill the effects region.

In this example, the image looks fine when it's stretched to fill the region, but that won't always be the case. In fact this image is actually much larger than the region it fills and is being compressed a great deal to fit, which I think helps it look ok despite being stretched.

Hopefully you agree it's rather easy to include the image in the filter and whether or not you want to preserve the aspect ratio will depend on the specifics of your filter and the effect you want to achieve.

The feTile Filter Primitive

The feTile filter primitive does what the name implies. It tiles an input image to fill the target rectangle (defined by the subregion of the feTile primitive) by repeating it in both the x and y directions.

There are no additional attributes beyond those common to most of the primitives so there's not a lot to learn to work with feTile. The main thing to keep in mind is the coordinates and dimensions of the different regions and the image you want to tile. Hopefully the next two examples will help illustrate.

Here I modified the example from the last section. We'll stick with one pair of rectangles (one that will get a filter and one to show the initial outline). I sized the Strawberry Fields image in the feImage primitive so it's 32px by 32px. The size was an arbitrary choice. I just wanted something smaller than the rectangle.

I set preserveAspectRatio to none so that the image would stretch to match the square dimensions of the filter effects region, which, again, is 32px in each direction.

1  2  3  4  5  6  7  8  9  10  
<svg width="100%" height="220" style="outline: 1px solid red">   <defs>     <filter id="tile" x="0" y="0" width="100%" height="100%">       <feImage xlink:href="http://www.vanseodesign.com/blog/wp-content/uploads/2013/09/strawberry-fields.jpg" result="strawberry-fields" width="32" height="32" preserveAspectRatio="none" />     </filter>   </defs>     <rect x="10" y="10" width="100" height="100" filter="url(#tile)" />   <rect x="10" y="10" width="100" height="100" fill="none" stroke="#00f" />  </svg>

You can see the result is a smaller image inside the input element, which is shown by the blue outline.

Now let's add the feTile primitive. In fact the only change between this and the previous example is the one line of code where I added <feTile in="strawberry-fields" result="tiled" /> You can see there's not a lot to using this primitive.

1  2  3  4  5  6  7  8  9  10  11  
<svg width="100%" height="220" style="outline: 1px solid red">   <defs>     <filter id="tile" x="0" y="0" width="100%" height="100%">       <feImage xlink:href="http://www.vanseodesign.com/blog/wp-content/uploads/2013/09/strawberry-fields.jpg" result="strawberry-fields" width="32" height="32" preserveAspectRatio="none" />       <feTile in="strawberry-fields" result="tiled" />     </filter>   </defs>     <rect x="10" y="10" width="100" height="100" filter="url(#tile)" />   <rect x="10" y="10" width="100" height="100" fill="none" stroke="#00f" />  </svg>

Here's the result, which you can see repeats the image both horizontally and vertically to fill the space. It probably looks like it fits exactly three times in the x and y directions, though it's actually starting a fourth repetition in each that gets cut after a few pixels.

You can create some interesting patterns, just by changing the size of the image. Here's the same example with the image set to width="10" and height="10" and leaving everything else the same.

That's a pretty big change for very little work and hopefully shows what you can do with feTile, just by varying the dimensions of whatever image or pattern you decide to tile.

Closing Thoughts

I hope you agree these two primitives are fairly easy to understand and work with. I also hope the last few examples show how filters become more interesting when you combine multiple filter primitives inside the same filter element.

Combining filters is going to be the subject of the next few posts in this series, which will look at several blend and merge filters, feMerge, feComposite, and feBlend. I'll show you the first next week and the latter two in the weeks after.

Download a free sample from my book Design Fundamentals.

Join me as I share my creative process and journey as a writer.

This posting includes an audio/video/photo media file: Download Now

Tuesday 18 October 2016

SVG Filter Effects—3 Simple Filter Primitives - Vanseo Design

SVG Filter Effects—3 Simple Filter Primitives - Vanseo Design


SVG Filter Effects—3 Simple Filter Primitives

Posted: 18 Oct 2016 05:30 AM PDT

For the last few weeks I've been talking about filters in SVG. I showed you the basics, talked in more detail about the filter element, and last week I discussed the input and output of filter primitives. What I haven't yet done is talk about any of the primitives in detail.

It's time to change that. Today I want to cover two primitives I've shown you already, feGaussianBur and feOffset, but in more detail than I've offered to this point. I'll also talk about a primitive we haven't seen yet, feFlood.

Next week I'll talk about two more primitives that are also simple to understand and use and allow you to work with external images and SVG fragments. In the weeks that follow I'll show you how you can blend and merge images and the effects SVG provides for working with color and lighting effects and finally a few more complex filters that don't fall under a specific category.

The feGaussianBlur Filter Primitive

The feGaussianBlur filter primitive does what you expect. It performs a Gaussian Blur on the input image or graphic. I'm guessing you've added blurs to images in your graphics editor of choice and have an idea what this primitive will do.

The feGaussianBlur filter primitive takes one attribute in addition to the common ones like in, result, and id. The additional attribute is stdDeviation and it's used in formulas behind the scenes to determine how much blur to apply.

1  
stdDeviation = <number-optional-number>

While you don't need to know the formulas, you should know that the larger the value of stdDeviation, the more blur.

In the examples so far in the series, I've used a single value, but stdDeviation can optionally take a second value. If you provide two numbers the first is the standard deviation along the x-axis and the second is along the y-axis. Both axes are those defined in the current coordinate system.

Negative values are not allowed and a value of 0 disables the effect. If you provide two values and only one of them is 0, then there will be no blur in that direction. Not setting any value for stdDeviation is the same as if you set the value to 0.

Since I've been using this primitive throughout the series and you may be tired of seeing the same example, let me try a variation of that example.

I created three squares using the <rect> element. The first has no filter applied. The second adds the blur filter with contains an feGaussianBlur primitive with a stdDeviation of 3.

The addition from previous examples is the third square which references the blurrier filter. It also contains an feGaussianBlur primitive, but instead of a single stdDeviation of 3, I changed the value in the x-direction only to 20.

1  2  3  4  5  6  7  8  9  10  11  12  13  14  15  
<svg width="100%" height="220" style="outline: 1px solid red">   <defs>     <filter id="blur">       <feGaussianBlur stdDeviation="3" />      </filter>       <filter id="blurrier">       <feGaussianBlur stdDeviation="20,3" />      </filter>  </defs>     <rect x="10" y="10" width="100" height="100" fill="#00f" />   <rect x="125" y="10" width="100" height="100" fill="#00f" filter="url(#blur)" />   <rect x="245" y="10" width="100" height="100" fill="#00f" filter="url(#blurrier)" />  </svg>

Here's the result. Notice that the third square has more blur applied in in the x-direction than the y-direction. You might also notice that because of the additional horizontal blue, this last square is looking less like a square and more like a horizontal rectangle.

One more thing I'll point out is the feGaussianBlur operation has no effect if the input has an infinite extent as some inputs like FillPaint have. As I mentioned last week, browser support for these infinite extent inputs isn't quite there and you probably don't want to use them as I'm writing this, but I thought I would mention it just in case you want to.

The feOffset Filter Primitive

The feOffset filter primitive takes an input and then offsets its location by an amount you specify. You set the amount through either or both of its attributes.

  • dx—amount to offset the input graphic along the x-axis
  • dy—amount to offset the input graphic along the y-axis

Not setting either is the same as if it was set to 0.

The values are in the coordinate system set by the primitiveUnites attribute of the filter element, which can either be userSpaceOnUse or objectBoundingBox. Keep that in mind if you set a value and the element moves by an unexpected amount. If it does, you're probably in the other coordinate system than what you thought.

Here's a quick example where I set a filter on a <rect> element that offsets the element by 50px in both the x and y direction. Note that I also increased the width and height of the filter effects region to 160% for each. Otherwise the square would be clipped at the edge of the default region.

1  2  3  4  5  6  7  8  9  
<svg width="100%" height="220" style="outline: 1px solid red">   <defs>     <filter id="offset" width="160%" height="160%">       <feOffset in="SourceGraphic" dx="50" dy="50" result="offset" />     </filter>   </defs>     <rect x="0" y="0" width="100" height="100" fill="#00f" filter="url(#offset)" />  </svg>

The original unfiltered element is positioned at the coordinates 0,0 which is the upper left corner of the SVG, but you can see the element sits away from this corner, which is the result of the feOffset filter primitive.

The feFlood Filter Primitive

The feFlood filter primitive lets you set or change both the fill color and opacity of the filtered element. The primitive creates a rectangle filled with the color and opacity values set with two properties, flood-color and flood-opacity.

1  2  
flood-color = ( currentColor | <color> \[<icccolor>] )  flood-opacity = ( <opacity-value> | inherit )

You can use any color as the value for flood-color (or use the currentColor) and flood-opacity takes a number between 0.0 and 1.0. If you're unfamiliar with currentColor, it's the computed value of the color property. I'm not entirely sure why you would use it in a filter, but I imagine there are some use cases.

The rectangle that's created by feFlood is as large as the filter primitive subregion. I talked about this subregion a couple weeks ago and you set it through the x, y, width, and height attributes on the filter primitive.

In this example I used the same blue square I've used as the source element throughout this series, but notice that I defined a filter effects region from 0 to 200% in both the x and y direction. I also set a filter primitive subregion that extends from 0,0 to 150,100. and filled this subregion with the color green and an opacity of 0.5.

1  2  3  4  5  6  7  8  9  
<svg width="100%" height="220" style="outline: 1px solid red">   <defs>    <filter id="flood" x="0" y="0" width="200%" height="200%">     <feFlood in="SourceGraphic" flood-color="green" flood-opacity="0.5" result="flood" x="0" y="0" width="150" height="100" />    </filter>   </defs>     <rect x="0" y="0" width="100" height="100" fill="#00f" filter="url(#flood)" />  </svg>

Even though the SourceGraphic is a 10px0 by 100px blue square, the filter fills in a slightly larger rectangle with a different color and opacity.

To reiterate, feFlood filled the primitive subregion which is 150px by 100px. That's larger than the original element which was 100px by 100px, but smaller than the filter effects region which extends 200% (200px in this example) in each direction.

Closing Thoughts

I'm guessing all three filter primitives I presented today were easy to understand. There's a reason I called this post 3 simple filter effects.

In a couple of weeks I'll show you how to combine feGaussianBlur and feOffset to create a drop shadow and later in the series I'll show more filter primitives for working with color.

But first I want to show you two more simple primitives that allow you to work with external images and SVG fragments inside filters. That's where I'll pick things up next week.

Download a free sample from my book Design Fundamentals.

Join me as I share my creative process and journey as a writer.

This posting includes an audio/video/photo media file: Download Now

Tuesday 11 October 2016

SVG Filter Primitives—Input and Output - Vanseo Design

SVG Filter Primitives—Input and Output - Vanseo Design


SVG Filter Primitives—Input and Output

Posted: 11 Oct 2016 05:30 AM PDT

SVG filter primitives are the building blocks to create the effect you desire. You can use multiple primitives inside a single filter for more interesting effects, however, you need to make the different primitives aware of each other.

For the last couple of weeks I've been talking about SVG filter effects. I started with an overview and then offered more details about the filter element, the region it affects, and the filter property that references it.

Today I want to focus on how filter primitives work, mainly how the output of one primitive can be used as the input for another inside the same filter. Starting next week, I'll dig into the details of the specific filters.

Input and Output of Filter Primitives

SVG filter primitives take an image or graphic element as input, perform an operation, and then output a resulting image or graphic. So far the examples in this series have taken a single graphic, referenced the id of a filter containing a single filter primitive, <feGaussianBlur>, inside. The filter altered the graphic and the output of the filter appeared on screen.

You aren't limited to the one filter primitive, though. You can take the result of one primitive and pass it to another. You can do that using the in and result attributes.

  • result—<filter-primitive-reference>
  • in —SourceGraphic | SourceAlpha | BackgroundImage | BackgroundAlpha | FillPaint | StrokePaint | <filter-primitive-reference>

The value of result is defined by you. You can give it any name you'd like. Note the result isn't an id. It only has local scope.

When you set the result on a filter primitive any subsequent primitive inside the same filter can access it through the in attribute. If, however, you don't supply a value for result the output of that primitive can only be passed implicitly to the very next primitive in the filter.

The in attribute identifies the input for the primitive. It can accept a number of values including the result of one of the primitives that comes before it in the filter and there are several other possible sources of input.

  • SourceGraphic —represents the original graphic that references the filter
  • SourceAlpha —represents the alpha channel only of the original graphic that references the filter
  • BackgroundImage —represents an image snapshot of the canvas under the filter region at the time that the filter element was invoked
  • BackgroundAlpha —represents the alpha channel of an image snapshot of the canvas under the filter region at the time that the filter element was invoked
  • FillPaint —represents the value of the fill property on the target element for the filter effect and it's conceptually infinite
  • StrokePaint —represents the value of the stroke property on the target element for the filter effect and it's also conceptually infinite
  • <filter-primitive-reference> —the name given to the output of a previous filter primitive in the same filter

Some of those definitions probably aren't all that clear so let's see if a few examples can help.

In this example I added a second filter primitive, <feOffset> to the example I've been working throughout this series. The feOffset primitive comes first and uses the SourceGraphic (the initial blue square) as its input (the value of in) and I've given its result the highly original name offset.

The feGaussianBlur primitive takes "offset" as the value of its in attribute and performs the blur. I gave this primitive a result too, though it's not really needed since I don't ever refer to its result in the filter.

1  2  3  4  5  6  7  8  9  10  11  12  
<svg width="100%" height="220" style="outline: 1px solid red">   <defs>    <filter id="io">     <feOffset in="SourceGraphic" dy="5" result="offset" />     <feGaussianBlur in="offset" stdDeviation="3" result="blur" />       </filter>   </defs>     <rect x="10" y="10" width="100" height="100" fill="#00f" />   <rect x="115" y="10" width="100" height="100" fill="#00f" filter="url(#io)" />  </svg>

Here's the result and you can see the blue square has been offset vertically as well as blurred.

Here's the example again, with one small change. Now the value of in for the feGaussianBlur is SourceGraphic instead of offset.

1  2  3  4  5  6  7  8  9  10  11  12  
<svg width="100%" height="220" style="outline: 1px solid red">   <defs>    <filter id="io2">     <feOffset in="SourceGraphic" dy="5" result="offset" />     <feGaussianBlur in="SourceGraphic" stdDeviation="3" result="blur" />       </filter>   </defs>     <rect x="10" y="10" width="100" height="100" fill="#00f" />   <rect x="115" y="10" width="100" height="100" fill="#00f" filter="url(#io2)" />  </svg>

Notice the result isn't offset like the previous example. The filter first performs the offset, but then the feGaussianBlur primitive ignores the result and uses for its input the initial source graphic which hasn't been offset.

Where SourceGraphic uses the original graphic as input, SourceAlpha uses only the alpha channel of the original graphic. In this example I changed feOffset to use SourceAlpha and have feGaussianBlur once again using the result of feOffset.

1  2  3  4  5  6  7  8  9  10  11  12  
<svg width="100%" height="220" style="outline: 1px solid red">   <defs>    <filter id="io3">     <feOffset in="SourceAlpha" dy="5" result="offset" />     <feGaussianBlur in="offset" stdDeviation="3" result="blur" />       </filter>   </defs>     <rect x="10" y="10" width="100" height="100" fill="#00f" />   <rect x="115" y="10" width="100" height="100" fill="#00f" filter="url(#io3)" />  </svg>

The result is now a blurry black square instead of a blue one. That's because the square is opaque (alpha = 1.0). Had the alpha channel of the original source been 0.5, you'd be looking at a blurry medium gray square.

SourceAlpha might not appear to be all that useful, but it allows us to create things like drop shadows. I'll show you an example when I cover the <feMerge> filter primitive in a couple of weeks.

The rest of the values for the in attribute will need a little more explanation.

Pseudo Inputs

The remaining four inputs BackgroundImage, BackgroundAlpha, FillPaint, and StrokePaint, are pseudo inputs. The idea being that the user agent would maintain these in a buffer and we'd be able to access what's inside the buffer. The first two, BackgroundImage and BackgroundAlpha, are meant to be accessible through an enable-background property.

Unfortunately the concept behind BackgroundImage and BackgroundAlpha was incompatible with CSS stacking context and no browser has implemented them and I don't think any intend to at this point. I mention both because they're still in the spec, even the SVG 2.0 spec.

The other two values, FillPaint and StrokePaint have some support. I've been able to access both in Firefox, which offers support. Because these pseudo inputs have infinite extent they fill the entirety of the filter effects region.

Here's an example, though you'll need to view it using Firefox to see the result. Most of the example should look familiar. The main thing to notice is the value of in, which is StrokePaint and that I've set the filterUnits to userSpaceOnUse.

1  2  3  4  5  6  7  8  9  10  
<svg width="100%" height="220" style="outline: 1px solid red">   <defs>     <filter id="pseudo" filterUnits="userSpaceOnUse">       <feGaussianBlur stdDeviation="3" in="StrokePaint" />     </filter>   </defs>     <rect x="10" y="10" width="100" height="100" fill="#00f" />   <rect x="115" y="10" width="100" height="100" fill="#0f0" stroke="#f00" filter="url(#pseudo)" />   </svg>

Here's the result, which again you'll need to view using Firefox. If you are you should see the entire viewport filled with the stroke color, red.

If you remove the filterUnits or set them back to ObjectBoundingBox, then the stroke color will display in a region 10% larger than the square on all four sides. You can also set specific x, y, width, and height values to control the location and size of ether pseudo input.

I haven't been able to get either to work in Chrome, Safari, or Opera. I haven't tested in Internet Explorer or Edge, but I don't think either offers support.

It's hard to know if support will grow or if FillPaint and StrokePaint will be like BackgroundImage and BackgroundAlpha. I would think support will grow, but that's up to the browsers and not me.

For now go ahead and use SourceGraphic, SourceAlpha, and any filter-primitive-reference you set, but hold off using BackgroundImage, BackgroundAlpha, FillPaint, and StrokePaint.

Closing Thoughts

I hope the last section didn't cause too much confusion. I debated even mentioning the pseudo inputs as values, but figured I would as they are still listed in the spec.

The main thing to take away from this post is that you can choose the input and output for each filter primitive, allowing you to chain a number of primitives together inside a single filter for more interesting effects.

However, before you can do that, you need to know the different filter primitives you can use. Next week I'll start to cover all the filter primitives in detail and with examples, beginning with a few simple filter effects, including a couple we've already seen.

Download a free sample from my book Design Fundamentals.

Join me as I share my creative process and journey as a writer.

This posting includes an audio/video/photo media file: Download Now

Tuesday 4 October 2016

The SVG Filter Element - Vanseo Design

The SVG Filter Element - Vanseo Design


The SVG Filter Element

Posted: 04 Oct 2016 05:30 AM PDT

SVG filter effects apply graphic operations to images and elements in nondestructive ways. You can add filters to any SVG element or text and even to bitmapped images. Because SVG filters are nondestructive the original image is never changed and you can return to it by removing any filters you've added.

Last week I started a series on SVG filters and I said SVG filters are composed of three parts, a filter element which contains one or more filter primitives that perform a graphic operation like blurring an image and finally a filter property that references the filter element and applies it to an image or graphic element.

Today I want to talk about the filter element and the filter property. In the following weeks I'll talk about filter primitives and their input and output. Then I'll walk you through each of the different filter primitives SVG provides with details and examples.

The Filter Property

Let's start with the filter property, since it doesn't need a lot of explanation. If you remember the example from the last post, I created a square using the <rect> element and referenced a filter on it.

1  
<rect x="115" y="10" width="100" height="100" fill="#00f" filter="url(#blur)" />

The filter="url(#blur)" part is the reference and this is the filter property. There's not much to it. Just note the syntax. The value takes the form url() and inside the parenthesis you list the id of the filter you want to add, in this case a filter with an id of blur.

You can add the filter property to any SVG element as well as SVG container elements (aside from the mask element).

That's all there is to the filter property, however I should note the filter property is not the only way to use a filter. You can also use the <use> element to reference a filter, which you might choose for filters that create their own elements or reference external images.

The Filter Element

The filter element is a container for filter primitives which do the actual work of modifying the display of an image or graphic element.

The filter element is never directly rendered. It's defined on its own and then used when referenced by the filter property of an SVG element or container. Because it's defined in one place and referenced in another, it's common, but not necessary, to wrap the filter element inside the <defs> element. I'll follow the convention throughout the series.

If the filter is referenced by a container element, such as a group <g>, the filter will apply to all the children inside the container. Otherwise it applies only to the element that referenced it.

Aside from some common attributes, such as id, that any SVG element can accept, the filter element can accept the following attributes and their possible values.

  • x—<coordinate>
  • y — <coordinate>
  • width — <length>
  • height — <length>
  • filterUnits — userSpaceOnUse | objectBoundingBox
  • primitiveUnits — userSpaceOnUse | objectBoundingBox
  • xlink:href — <iri>

All of these attributes might look familiar. It seems like every SVG element takes coordinates and lengths and if you've done any work with SVG, you've likely encountered different kinds of units and here are two more filterUnits and primitiveUnits.

To explain these and the other attributes as they apply to the filter element we need to talk a little about the filter effects region.

The Filter Effects Region

The filter effects region is a region on the SVG canvas where a given filter applies. It doesn't have to be the same region occupied by the element referencing the filter. Most of the attributes on the filter element define the filter effects region.

I think an example will help make this clearer. In the example from last week I defined a filter with a single filter primitive that added a Gaussian blur. The filter had an id of blur, which was referenced by the second of two rectangles using the filter property.

That's the review part. What I've added since last week are the x, y, width, and height attributes to the filter element.

1  2  3  4  5  6  7  8  9  10  
<svg width="100%" height="220" style="outline: 1px solid red">  <defs>   <filter id="blur" x="-10%" y="-10%" width="120%" height="120%">    <feGaussianBlur stdDeviation="3" />   </filter>  </defs>    <rect x="10" y="10" width="100" height="100" fill="#00f" />  <rect x="115" y="10" width="100" height="100" fill="#00f" filter="url(#blur)" />  </svg>

Here's the result and if you remember last week's example you might notice the result here looks exactly the same. That's because I used the default values for each attribute so this example ends up being the same as not having including them.

The values of x, y, width, and height create a region of space, inside of which, the filter effect applies. In this example that area starts 10% to the left and above the rectangle and it ends 10% to the right and below the rectangle.

Let's see what happens if we change one of values. Here I changed the value of y from –10% to 0%. Notice that the square on the right no longer has a blurry top edge. That's because the filter, which used to start 10% above this top edge, now starts exactly where the top edge starts.

What happens if I change y to 10%? Now the top 10% of the square is gone.

Hopefully you get the idea. Similar things happen if we change x, width, or height. The initial values of –10% and 120% ensure the effect applies to an area 10% larger than the element being filtered. Any changes to these values modifies the location and dimensions of the affected region.

The boundaries of the filter effects region act like a hard clipping area, which is why the top 10% of the square in the second example disappeared. It's outside the region and gets clipped.

Be aware that the filter effect itself might extend outside the boundary of the element referencing it. That's the case with the Gaussian blur, which is why a value of 0 for y clipped the effect, even though it didn't clip the square.

Because of the potential to clip the element that takes the filter, you might think it best to create a larger filter effects region than you think you'll need. However, the amount of memory and processing time required to apply a filter are related to the size of the filter effects region so a larger region could be a performance hit.

As you can tell from the examples x and y can be negative numbers. That's not true for width and height which must be positive. You might also have noticed that I set all four (x, y, width, and height) using percents. That's because of the next attribute, filterUnits.

The filterUnits attribute defines the coordinate system for x, y, width, and height. It accepts one of two values userSpaceOnUse or objectBoundingBox.

  • userSpaceOnUse—represents values in the current user coordinate system in place at the time when the filter is referenced
  • objectBoundingBox — represents fractions or percentages of the bounding box on the referencing element

The latter is the default, which is why I used percents in the previous example. Here's the example again with the filterUnits set to userSpaceOnUse and the values for x, y, width, and height adjusted.

1  2  3  4  5  6  7  8  9  10  
<svg width="100%" height="220" style="outline: 1px solid red">  <defs>   <filter id="blur4" x="105" y="0" width="120px" height="120px" filterUnits="userSpaceOnUse">    <feGaussianBlur stdDeviation="3" />   </filter>  </defs>    <rect x="10" y="10" width="100" height="100" fill="#00f" />  <rect x="115" y="10" width="100" height="100" fill="#00f" filter="url(#blur4)" />  </svg>

I set the filter effects region so it would be 10px larger than the square all around. The top left corner of the square is located 115px from the left edge of the viewport and 10px from the top leading to the values of 105px and 0px for x and y. Since the square is 100px by 100px, values of 120px each for width and height extend the filter effects region 10px past the edge of the square on the right and bottom.

Here's the result, which should look like the result of the earlier example.

The Filter Primitive Subregion

The primitiveUnits attribute is similar to filterUnits, but as you might guess it affects the filter primitives instead of the filter. The attribute is still added to the filter element and it takes the same userSpaceOnUse or objectBoundingBox values.

The default value is userSpaceOnUse, which is the opposite of the filterUnits attribute. This means the default filter primitive subregion is the same size as the default filter effects region. You can, of course, change the default.

Here I changed the primitiveUnits to objectBoundingBox and then set the subregion to fall an extra 10% outside of the element.

1  2  3  4  5  6  7  8  9  10  
<svg width="100%" height="220" style="outline: 1px solid red">   <defs>    <filter id="blur5" primitiveUnits="objectBoundingBox">     <feGaussianBlur stdDeviation="0.033" x="-10%" y="-10%" width="120%" height="120%" />    </filter>   </defs>     <rect x="10" y="10" width="100" height="100" fill="#00f" />   <rect x="115" y="10" width="100" height="100" fill="#00f" filter="url(#blur5)" />  </svg>

You may have noticed I changed the stdDeviation of the feGaussianBlur from 3 to 0.33. That was to accommodate the new subregion units, which you'll also note was set by adding x, y, width, and height to the primitive itself.

As with the filter effects region, the filter primitive subregion acts as a hard clipping area. Here's the previous example with a change in the height from 120% to 60%. You can see the bottom of the second square has been clipped.

xlink:href

The remaining attribute, xlink:href, is a way to refer to another filter element within the current SVG fragment. However, I've yet to get this attribute to work directly on the filter element and I've yet to find an example anywhere where it's used this way.

The xlink:href attribute does work on other elements like <use> and <image> and it will also work on the filter primitive <feImage>, which I'll get to in a few weeks, but not directly on the <filter> element itself as far as I can tell. If you know of a working example, please point me to it.

Closing Thoughts

There are two things to take away from this post. First is the idea that the filter element is a container for filter primitives and it's the primitives that perform the graphic operation.

Second is the idea of the filter effects region and filter primitive subregion, which you define using the x, y, width, and height attributes added to the filter element or the filter primitives inside it.

Both act like a hard clipping path so you want to make sure they're large enough to include the filter effect you want to apply, but not any larger as it will take up more processing power to apply the filter over a larger area.

You can also change the coordinate system through the filterUnits and/or primitiveUnits attributes so either region can be relative to the viewport or relative to the element being filtered.

I have a few more things to say about filter primitives, specifically their input and output and how the output of one primitive can be used as the input of another. That will be the topic for next time.

Download a free sample from my book Design Fundamentals.

Join me as I share my creative process and journey as a writer.

This posting includes an audio/video/photo media file: Download Now