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.