If I use 'SourceGraphic' as in2 inside feDisplacementMap, things looks good. However, if I use anything else, the deformation is not applied.
Because of that, I have to define the deformation source first, and then apply the filter to the deformation source, which is quite counter-intuitive, at least for me.
For example, in the example below I have to define the circle and then apply the filter to the circle. Inside the filter I use feImage to load the kitten image. But that feels reverse to me. This works:
<svg>
<defs>
<filter id="displace">
<feImage href="https://placekitten.com/500/500" result="kitten" />
<feDisplacementMap
scale="10"
xChannelSelector="R"
yChannelSelector="R"
in="kitten"
in2="SourceGraphic"
/>
</filter>
</defs>
<circle cx="50" cy="50" r="50" fill="#f00" filter="url(#displace)" />
</svg>
As you can see, applying a displacement to a small part of an image becomes quite painful, as you have to first create the displacement map yourself, and it must have the same size as the image. Like this:
<g id="deformation-source" filter="url(#displace)">
<rect x="0" y="0" width={imageWidth} height={imageHeight} fill={neutralToDeformation} />
<circle cx="50" cy="50" r="50" fill="#f00" filter="url(#displace)" />
</g>
Also, applying 2 different deformations to the same image, requires you to put the objects that will cause the deformation, instad of doing something like this:
<image href="kitten-url" filter="url(#filter-1)" />
<image href="kitten-url" filter="url(#filter-2)" />
What I would like to be able to do is to load the kitten as an SVG image tag, and then apply the filter to that image, where I would load the circle inside a feImage making a reference to the object's id, which I would have previously defined inside the defs section. This doesn't work:
<svg>
<defs>
<circle id="displacement-source" cx="50" cy="50" r="50" fill="#f00" />
<filter id="displace">
<feImage href="displacement-source" result="displacement-source" />
<feDisplacementMap
scale="10"
xChannelSelector="R"
yChannelSelector="R"
in="SourceGraphic"
in2="displacement-source"
/>
</filter>
</defs>
<image href="https://placekitten.com/500/500" width="100" filter="url(#displace)" />
</svg>
I'm not sure if I'm the one that's thinking this backwards or if I'm missing something. What's going on with this?
You can define your displacement source within the feImage, but it has to be an complete image defined as an inline URI in order to be cross browser compatible.
<feImage width="500" height="500" xlink:href="data:image/svg+xml,%3Csvg width='247' height='34'etc. etc.
Please see this article for more detail on how to escape characters in the svg+xml format - as far as I can remember there are some gotchas vs. vanilla HTML escaping.
If you don't care about Firefox, you can use a fragment identifier instead of inlining a whole SVG.
<feImage width="500" height="500" xlink:href="#idOfElementYouWantToUse"/>
Also remember that there are cross-origin security rules on displacementMap sources - so you can't displace an image using a map from another domain (or vice versa - I'm a little hazy on which way the restrictions run).
Related
Currently working on a project that uses a slider to compare two different images overlaid with SVG's. SVG's on the right side of the slider have a mask applied to them while the SVG's on the left should remain unchanged.
My problem is that when using a mask to apply these styles the mask clips any of the element that it doesn't cover.
Reproduction CodePen: https://codepen.io/anon/pen/VNEOPy
Super minimal repro:
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="200px" height="200px">
<defs>
<pattern
id="pattern"
width="10"
height="10"
patternUnits="userSpaceOnUse"
>
<circle cx="5" cy="5" r="5" fill="#999"></circle>
</pattern>
<mask id="masker">
<rect x="0" y="0" width="25%" fill="url(#pattern)"></rect>
</mask>
</defs>
<circle cx="50" cy="50" r="50" mask="url(#masker)"></circle>
</svg>
What I would like to do is apply the mask to the portion of the element that the mask covers and allow the rest of the element to remain visible/unchanged.
This CodePen demonstrates the behavior I am looking for, but requires duplicating each of the SVG's (which is unfortunately not technically feasible in my case): https://codepen.io/anon/pen/vMzwbP
Is there a way to achieve this behavior with masking? Am I looking in the wrong place?
No. You are always going to have to have two instances of the circle. One with the mask applied, and one with no mask (or the inverse mask).
I have an SVG filter that overlays an image with a spinner. This works fine, except I cannot figure out how to center the spinner on the image. The logical answer seems to be:
<filter id="loading" primitiveUnits="objectBoundingBox">
<feImage xlink:href="filters.svg#loading-overlay" x="50%" y="50%" result="spinner" />
<feOffset in="spinner" result="offsetSpinner" dx="-25px" dy="-25px" />
<feBlend in2="SourceGraphic" in="offsetSpinner" />
</filter>
But of course you can't use "-25px" as an argument to feOffset.
Anybody have a clever solution?
Fiddle: https://jsfiddle.net/pytmd8tr/
(As a matter of opinion - I think the way primitiveUnits works is really stupid. In particular, it makes no sense to specify things like the stdev of a blur as a % of the original image. Maybe I'm missing something obvious?)
Well you can use JavaScript to calculate the right %'s and insert them, but failing that - something like this should work. (Although feImage sizing & positioning can have bugs in IE10).
<filter id="loading" primitiveUnits="objectBoundingBox">
<feImage xlink:href="#loading-overlay" x="25%" y="25%" width="50%" height="50%" result="spinner" />
<feBlend in2="SourceGraphic" in="spinner" result="foo" />
</filter>
Really basic SVG question. I have read
SVG sprite in external file
and it works fine for me to add a svg graphic, but I can't get it to work with defs. First the file 'defs.svg':
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" >
<defs id='patternDefs'>
<pattern id="pattern1"
x="2" y="2"
width="5" height="5"
patternUnits="userSpaceOnUse" >
<circle cx="2" cy="2" r="2" class="blue" />
</pattern>
</defs>
</svg>
and then the svg in a separate file:
<svg>
<use xlink:href="defs.svg#patternDefs"></use>
<circle cx="15" cy="15" r="50" stroke-width="2" stroke="red" fill="url(#pattern1)" />
</svg>
I am looking to get the fill="url(#pattern1)" part to work, as that is what is referencing the def in the external file.
Sorry if you think this has been answered elsewhere but I've read a ton of stuff and thought that if I could get the sprite version to work then why not a defs version. (I am very new to svg)
xlink:href="defs.svg#patternDefs" should be xlink:href="defs.svg#pattern1"
On top of that <use> has to point to something to be rendered, not a pattern. If you want to fill a circle with a pattern just set the circle's fill to the pattern. E.g.
<svg>
<circle cx="80" cy="80" r="50" stroke-width="2" stroke="red" fill="url(defs.svg#pattern1)" />
</svg>
Note that external fills are not widely supported, although they do work on Firefox for instance.
I would like to share coordinates between two or more elements.
My example in peudo-Code :
<point xml:id="myPoint" x="10" y="20" />
<circle point="url(#myPoint)" r="10" />
<circle point="url(#myPoint)" r="50" />
I've seen IRI references that have the best match with that I searched, but :
First, there is no nodes of type "point" existing.
Second, IRI references doesn't support any attributes.
With SVG format and specifications (no javascript code), Is there a way to have many elements which reference the same coordinates ?
Thus, I just have to manipulate the point "myPoint" to change the coordinate of all elements that reference it.
I hope my english isn't so bad and thanks for your answers.
Use a group <g> element to transform the origin. If you omit co-ordinates then objects will be drawn there.
<g transform="translate(10, 20)">
<circle r="10" />
<circle r="50" />
</g>
I'd like to create a list of locations markers on an svg graphic that I can call upon, using the id, to place content at dynamically.
what is the best way of achieving this?
I'm thinking of using an empty def like this:
<defs>
<g id="coord"></g>
</defs>
<use xlink:href="#coord" id="L1" x="10" y="10" />
<use xlink:href="#coord" id="L2" x="100" y="100" />
Is there another way of doing this?
Is there any visual editor that can be used to generate use elements and assign ids?
I think a simpler approach would be to use something like:
<circle id="L1" cx="10" cy="10" r="0" />
Without a radius (and assuming there is no stroke-width in effect), they won't be visible.
And if you put them in their own group or layer in your Inkscape file, you can temporarily give them all a stroke-width or non-zero radius if you want to edit them. Then reset them back when you save the final version.