2

Я пытаюсь сгенерировать градиент, который я мог бы использовать в качестве входных данных для фильтра feDisplacementMap для искажения текста в SVG. Как мне это реализовать?

Я пытался создать его, как часть SVG и скрыть градиент, но не могу заставить его работать таким образом.

<svg
          filter="url(#f)"
          overflow="auto"
          viewBox="0,0,200vw,200vh"
          width="100%"
          height="100vh"
        >
          <defs>
            <radialGradient id="rg" r=".9">
              <stop offset="0%" stop-color="#f00"></stop>
              <stop offset="10%" stop-color="#000"></stop>
              <stop offset="20%" stop-color="#f00"></stop>
              <stop offset="30%" stop-color="#000"></stop>
              <stop offset="40%" stop-color="#f00"></stop>
              <stop offset="50%" stop-color="#000"></stop>
              <stop offset="60%" stop-color="#f00"></stop>
              <stop offset="70%" stop-color="#000"></stop>
              <stop offset="80%" stop-color="#f00"></stop>
              <stop offset="90%" stop-color="#000"></stop>
              <stop offset="100%" stop-color="#f00"></stop>
            </radialGradient>
        &lt;filter id="f" primitiveUnits="objectBoundingBox"&gt;
          &lt;feImage result="pict2" xlink:href="#witness"&gt;&lt;/feImage&gt;
          &lt;feDisplacementMap
            scale=".05"
            xChannelSelector="R"
            yChannelSelector="R"
            in2="pict2"
            in="SourceGraphic"
          &gt;&lt;/feDisplacementMap&gt;
        &lt;/filter&gt;

        &lt;pattern id="imageFill" width="1" height="1" viewBox="0 0 300 300"&gt;
          &lt;image id="ripples" width="300" height="300" xlink:href="" /&gt;
        &lt;/pattern&gt;
      &lt;/defs&gt;
      &lt;text height="100vh" text-anchor="middle" class="svgText"&gt;
        &lt;tspan height="100vh" x="50%" y="50%"&gt;text&lt;/tspan&gt;
      &lt;/text&gt;
      &lt;rect
        id="witness"
        width="100%"
        height="100%"
        stroke="none"
        opacity="0"
        fill="url(#rg)"
      /&gt;
    &lt;/svg&gt;</code></pre>

Я хотел бы иметь возможность искажать текст сгенерированным градиентом, сохраняя его скрытым.

Свободный перевод вопроса Is there a way to use a SVG gradient as input to a displacement map? от участника @rui.

Alexandr_TT
  • 110,146
  • 23
  • 114
  • 384

2 Answers2

2

Для того, чтобы фильтр работал, вам нужно использовать данные URI для feImage.
Я использую ваш градиент, но фильтр, который вы используете, имеет небольшой размер.
Я применяю - scale = "15"

<svg width="300" height="300">
<defs>
<filter id="f" filterUnits="userSpaceOnUse" x="0" y="0" width="300" height="300">
      <feImage xlink:href="data:image/svg+xml;utf8,%3Csvg width='300' height='300' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'%3E%3Cdefs%3E %3CradialGradient id='rg' r='.7'%3E %3Cstop offset='0%25' stop-color='%23f00'%3E%3C/stop%3E%3Cstop offset='10%25' stop-color='%23000'%3E%3C/stop%3E%3Cstop offset='20%25' stop-color='%23f00'%3E%3C/stop%3E%3Cstop offset='30%25' stop-color='%23000'%3E%3C/stop%3E%3Cstop offset='40%25' stop-color='%23f00'%3E%3C/stop%3E%3Cstop offset='50%25' stop-color='%23000'%3E%3C/stop%3E%3Cstop offset='60%25' stop-color='%23f00'%3E%3C/stop%3E%3Cstop offset='70%25' stop-color='%23000'%3E%3C/stop%3E%3Cstop offset='80%25' stop-color='%23f00'%3E%3C/stop%3E%3Cstop offset='90%25' stop-color='%23000'%3E%3C/stop%3E%3Cstop offset='100%25' stop-color='%23f00'%3E%3C/stop%3E% %3C/radialGradient%3E%3C/defs%3E%3Crect fill='url(%23rg)' width='300' height='300'%3E%3C/rect%3E%3C/svg%3E" result="pict2"/>
      <feDisplacementMap scale="15" xChannelSelector="R" yChannelSelector="R" in2="pict2" in="SourceGraphic"/>
   </filter> 
</defs>

<image xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="https://s3-us-west-2.amazonaws.com/s.cdpn.io/222579/beagle400.jpg" height="300" width="300" filter="url(#f)" /> </svg>

Также в вашем коде есть несколько ошибок:

  1. viewBox аттрибут не может иметь наименование данных. Это не будет работать: viewBox="0,0,200vw,200vh"
  2. Также вы не можете написать: <text height="100vh" или: <tspan height="100vh", однако вы можете указать размер шрифта для вашего текста.

Свободный перевод ответа от участника @enxaneta.

Alexandr_TT
  • 110,146
  • 23
  • 114
  • 384
2
  • Применяем радиальный градиент :

.container {
width:100%;
height:100%;
}
#txt1 {
font-size: 200px;
font-weight:bold;
font-family: 'Signika', sans-serif;
fill:url(#rg);
}
<div class="container">
<svg viewBox="0 0 750 300"    xmlns="http://www.w3.org/2000/svg"  
xmlns:xlink="http://www.w3.org/1999/xlink">
&lt;defs&gt;
  &lt;radialGradient id="rg" r=".9"&gt;
          &lt;stop offset="0%" stop-color="#f00"&gt;&lt;/stop&gt;
          &lt;stop offset="10%" stop-color="#000"&gt;&lt;/stop&gt;
          &lt;stop offset="20%" stop-color="#f00"&gt;&lt;/stop&gt;
          &lt;stop offset="30%" stop-color="#000"&gt;&lt;/stop&gt;
          &lt;stop offset="40%" stop-color="#f00"&gt;&lt;/stop&gt;
          &lt;stop offset="50%" stop-color="#000"&gt;&lt;/stop&gt;
          &lt;stop offset="60%" stop-color="#f00"&gt;&lt;/stop&gt;
          &lt;stop offset="70%" stop-color="#000"&gt;&lt;/stop&gt;
          &lt;stop offset="80%" stop-color="#f00"&gt;&lt;/stop&gt;
          &lt;stop offset="90%" stop-color="#000"&gt;&lt;/stop&gt;
          &lt;stop offset="100%" stop-color="#f00"&gt;&lt;/stop&gt;
        &lt;/radialGradient&gt;
&lt;/defs&gt;
&lt;text id="txt1" x="15%" y="75%"  &gt;Stack&lt;/text&gt;

</svg> </div>

  • Добавляем фильтры: feTurbulence и feDisplacementMap

Изменяя значения атрибутов фильтра feTurbulence - baseFrequency и scale фильтра -feDisplacementMap , вы можете получить интересные эффекты

Анимация стартует когда вы наводите курсор на текст: begin ="txt1.mouseover" и заканчивается, когда уводите курсор: end ="txt1.mouseout" или по истечению времени - dur ="18s"

Ниже пример анимации искажения текста:

.container {
background-color:blue;
}
#txt1 {
font-size: 200px;
font-weight:bold;
font-family: 'Signika', sans-serif;
fill:url(#rg);
filter:url(#myFilter);
}
<div class="container">
<svg  width="750" height="300" version="1.1"
viewBox="0 0 750 300"    xmlns="http://www.w3.org/2000/svg"  xmlns:xlink="http://www.w3.org/1999/xlink">
&lt;defs&gt;
   &lt;radialGradient id="rg" r=".9"&gt;
          &lt;stop offset="0%" stop-color="#f00"&gt;&lt;/stop&gt;
          &lt;stop offset="10%" stop-color="#000"&gt;&lt;/stop&gt;
          &lt;stop offset="20%" stop-color="#f00"&gt;&lt;/stop&gt;
          &lt;stop offset="30%" stop-color="#000"&gt;&lt;/stop&gt;
          &lt;stop offset="40%" stop-color="#f00"&gt;&lt;/stop&gt;
          &lt;stop offset="50%" stop-color="#000"&gt;&lt;/stop&gt;
          &lt;stop offset="60%" stop-color="#f00"&gt;&lt;/stop&gt;
          &lt;stop offset="70%" stop-color="#000"&gt;&lt;/stop&gt;
          &lt;stop offset="80%" stop-color="#f00"&gt;&lt;/stop&gt;
          &lt;stop offset="90%" stop-color="#000"&gt;&lt;/stop&gt;
          &lt;stop offset="100%" stop-color="#f00"&gt;&lt;/stop&gt;
        &lt;/radialGradient&gt;
   &lt;filter id="myFilter" &gt;
     &lt;feTurbulence type="turbulence" baseFrequency="0.0001" numOctaves="1" result="turbulence" &gt;
      &lt;animate attributeName="baseFrequency"
        dur="18s"
        values="0.0001;0.02;0.0001;0.02;0.0001"
        begin="txt1.mouseover"
        end="txt1.mouseout" /&gt;
  &lt;/feTurbulence&gt;
 &lt;feDisplacementMap xChannelSelector="R" yChannelSelector="G" scale="25" in="SourceGraphic" in2="turbulence" /&gt;
&lt;/filter&gt;
&lt;/defs&gt;
&lt;text id="txt1" x="1%" y="50%"  &gt;Stack&lt;/text&gt;

</div>

  • Пример анимации искажения картинки и текста:

Наведите курсор на изображение

.container {
width:75%;
height:75%;
}

#txt1 { font-size: 100px; font-weight:bold; font-family: 'Signika', sans-serif; fill:url(#rg); filter:url(#myFilter); pointer-events:none; }

<div class="container">
<svg xmlns="http://www.w3.org/2000/svg" version="1.1"   viewBox="0 0 500 300">
  <defs> 
  <radialGradient id="rg" r=".9">
              <stop offset="0%" stop-color="#f00"></stop>
              <stop offset="10%" stop-color="#000"></stop>
              <stop offset="20%" stop-color="#f00"></stop>
              <stop offset="30%" stop-color="#000"></stop>
              <stop offset="40%" stop-color="#f00"></stop>
              <stop offset="50%" stop-color="#000"></stop>
              <stop offset="60%" stop-color="#f00"></stop>
              <stop offset="70%" stop-color="#000"></stop>
              <stop offset="80%" stop-color="#f00"></stop>
              <stop offset="90%" stop-color="#000"></stop>
              <stop offset="100%" stop-color="#f00"></stop>
            </radialGradient>
    <filter id="myFilter" >
      <feTurbulence type="turbulence" baseFrequency="0.0001" numOctaves="1" result="turbulence" >
     <animate attributeName="baseFrequency" dur="18s" values="0.0001;0.02;0.0001;0.02;0.0001" begin="img1.mouseover" end="img1.mouseout" />
      </feTurbulence>
     <feDisplacementMap xChannelSelector="R" yChannelSelector="G" scale="25" in="SourceGraphic" in2="turbulence" />
    </filter>
  </defs>
<image id="img1" xlink:href="https://i.stack.imgur.com/hHGO8.jpg" width="100%" height="100%" filter="url(#myFilter)" /> 
   <text id="txt1" x="35%" y="35%"  >Stack</text>
  </svg>
</div>

Связанный вопрос: Canvas / Создание эффекта (маски) миража для изображения

Свободный перевод ответа от участника @Alexandr_TT.

Alexandr_TT
  • 110,146
  • 23
  • 114
  • 384