feDisplacementMap

facebook-svg gplus-svg twitter-svg

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.