feDisplacementMap
El filtro primitivo <feDisplacementMap> utiliza el valor de los pixeles de la imagen in2 para desplazar los pixeles de la imagen in.
<feDisplacementMap in2="img1" in="img2" scale="15" xChannelSelector="R" yChannelSelector="G"/>
El atributo scale define la magnitud del desplazamiento.
Los atributos xChannelSelector y yChannelSelector pueden tomar uno de estos valores: R ( para rojo ), G ( de green – para verde ), B ( de blue para el azul ) o A ( de alpha para la transparencia ).
El atributo xChannelSelector indica el canal de color ( R,G,B o A ) de in2 que tiene que utilizarse para desplazar los pixeles de in a lo largo del eje x, mientras que el atributo yChannelSelector indica el canal de color ( R,G,B o A ) de in2 que tiene que utilizarse para desplazar los pixeles de in a lo largo del eje y.
Un ejemplo fácil
En el siguiente ejemplo primero creamos un patrón de cuadros para utilizarlo como relleno ( fill ) de un rectángulo ( rect ):
<pattern id='deCuadros' width='40' height='40' patternUnits="userSpaceOnUse">
<rect width='20' height='20' style='stroke:black;stroke-width:1;fill:red'/>
<rect x='20' y='20' width='20' height='20' style='stroke:black; stroke-width:1; fill:red'/>
</pattern>
Creamos un grupo de dos elementos: un rectángulo blanco, y otro cuyo relleno es el patrón #deCuadros:
<g id="grupo">
<rect width="300" height="300" fill="white"/>
<rect width="300" height="300" fill="url(#deCuadros)"/>
</g>
A continuación creamos el filtro #filtroDeCuadros.
<filter id="filtroDeCuadros" filterUnits="userSpaceOnUse" x="0" y="0" width="300" height="300"> <feImage xlink:href='#grupo' result='img'/> <feDisplacementMap scale="15" xChannelSelector="R" yChannelSelector="G" in2="img" in=" SourceGraphic "/> </filter>
Utilizamos feImage para importar el #grupo creado anteriormente:
<feImage xlink:href='#grupo' result='img'/>
Finalmente utilizamos el valor de los pixeles del grupo ( result='img' ) para desplazar los pixeles del grafico de origen ( in="SourceGraphic" ).
<feDisplacementMap scale="15" xChannelSelector="R" yChannelSelector="G" in2="img" in="SourceGraphic"/>
See the Pen SVG feImage feDisplacementMap #1* by Gabi (@enxaneta) on CodePen.
Esto funciona pero no en Fierfox. Afortunadamente sabemos porque y sabemos como arreglarlo.
Lea más acerca de feImage y el bug 455986
Solucionar el problema
Podemos solucionar este problema utilizando SVG como dataURI en lugar de fragmentos.
Sabemos que la imagen SVG que queremos utilizar es el #grupo.
See the Pen grupo de cuadros* by Gabi (@enxaneta) on CodePen.
Para transformar un elemento SVG a dataURI hay que seguir unas cuantas reglas:
a. Lo ponemos todo entre comillas dobles ( " ) y ponemos los atributos entre comillas sencillas ( por ejemplo height = '122px' ). De esta manera no tendremos que escaparlas. También quitamos los espacios de línea.
"<svg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' width='300' height='300'><defs><pattern id='deCuadros' x='0' y='0' width='40' height='40' patternUnits='userSpaceOnUse'><rect x='0' y='0' width='20' height='20' style='stroke:black;stroke-width:1;fill:red'/><rect x='20' y='20' width='20' height='20' style='stroke:black; stroke-width:1; fill:red;'/></pattern></defs><g id='grupo'><rect x='0' y='0' width='300' height='300' fill='white'/><rect x='0' y='0' width='300' height='300' fill='url(#deCuadros)'/></g></svg>"
b. Ciframos los caracteres no-alfanuméricos, los así llamados caracteres reservados o caracteres inseguros ( unsafe in URLs characters ) pero no los espacios en blanco:
< se transforma en %3C
> se transforma en %3E
Por ejemplo <svg> vuelve a ser %3Csvg%3E
# se transforma en %23
Por ejemplo fill = '#abcdef' vuelve a ser fill = '%23abcdef'
el guión - se transforma en %2D
Por ejemplo stroke-width='2' vuelve a ser stroke%2Dwidth='2'
el símbolo matemático porciento % se transforma en %25
Por ejemplo width ='50%' vuelve a ser width ='50%25'
"%3Csvg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' width='300' height='300'%3E%3Cdefs%3E%3Cpattern id='deCuadros' x='0' y='0' width='40' height='40' patternUnits='userSpaceOnUse'%3E%3Crect x='0' y='0' width='20' height='20' style='stroke:black;stroke%2Dwidth:1;fill:red'/%3E%3Crect x='20' y='20' width='20' height='20' style='stroke:black; stroke%2Dwidth:1; fill:red;' /%3E%3C/pattern%3E%3C/defs%3E%3Cg id='grupo'%3E%3Crect x='0' y='0' width='300' height='300' fill='white'/%3E%3Crect x='0' y='0' width='300' height='300' fill='url(%23deCuadros)'/%3E%3C/g%3E%3C/svg%3E"
A continuación necesitamos indicar al navegador que lo que viene a continuación es un dataURI, ( data: ) y que se trata de una imagen SVG ( image/svg+xml ).
"data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' width='300' height='300' . . ."
Normalmente cuando utilizamos SVG en HTML5 no utilizamos espacios de nombres ( namespace ), pero en este caso es importante utilizarlos. No olvidemos que, al fin y al cabo, los data:uri son el equivalente a una referencia hacia una fuente externa.
"data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' width='300' height='300' . . ."
Y con esto tendría que bastar. Ahora en lugar de esto:
<feImage xlink:href='#grupo' result='img'/>
tenemos que utilizar esto:
<feImage xlink:href="data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' width='300' height='300'%3E%3Cdefs%3E%3Cpattern id='deCuadros' x='0' y='0' width='40' height='40' patternUnits='userSpaceOnUse'%3E%3Crect x='0' y='0' width='20' height='20' style='stroke:black;stroke%2Dwidth:1;fill:red'/%3E%3Crect x='20' y='20' width='20' height='20' style='stroke:black;stroke%2Dwidth:1;fill:red'/%3E%3C/pattern%3E%3C/defs%3E%3Cg id='grupo'%3E%3Crect x='0' y='0' width='300' height='300' fill='white'/%3E%3Crect x='0' y='0' width='300' height='300' fill='url(%23deCuadros)'/%3E%3C/g%3E%3C/svg%3E" result="img2"/>
Y ahora sí que funciona:
See the Pen SVG feImage feDisplacementMap #2* by Gabi (@enxaneta) on CodePen.
Vea más ejemplos se filtros SVG que utilizan el filtro primitivo feDisplacementMap.
See the Pen SVG feImage feDisplacementMap by Gabi (@enxaneta) on CodePen.