Есть ли способ применения фильтра SVG с определенной формой? - PullRequest
1 голос
/ 07 июня 2019

Я экспериментирую с SVG-фильтром, чтобы получить хорошие анимации и эффекты. Это новый мир, который я только что открыл, но я столкнулся с проблемой. Я пытаюсь воспроизвести этот вид эффекта: https://www.youtube.com/watch?v=GcSU4xH6_Ro
Я не знаю, как воспроизвести круг с искажением.

Я знаю, что могу поиграть с filter и svg, но на самом деле, если я применяю свой svg filter к блоку, все div будут затронуты, вместо этого круга.

Интересно, можно ли заставить svg действовать как "линза"? Я сделал jsFiddle, если вы хотите увидеть код: https://jsfiddle.net/wekhz7rb/

Я хотел бы сделать это только с CSS

    <div class="box">
    <svg class="svg" xmlns="http://www.w3.org/2000/svg" id="effect"     
     width="275px" height="275px">
    <filter id="noise">
    <feTurbulence baseFrequency="0.05" numOctaves="2" result="noise">    
    </feTurbulence>
    <feComposite operator="in" in2="SourceGraphic"></feComposite>
    <feDisplacementMap in="SourceGraphic" in2="noise" scale="50">        
    </feDisplacementMap>
    </filter>
    <!-- <circle cx="137" cy="137" r="137" fill="red" filter="url(#noise)">            
    </circle> -->
    </svg>
    <div class="text">DREAMS</div>
    <div class="text">DREAMS</div>
    <div class="text">DREAMS</div>
    <div class="text">DREAMS</div>
    <div class="text">DREAMS</div>
    <div class="text">DREAMS</div>
    <div class="text">DREAMS</div>
    <div class="text">DREAMS</div>
    <div class="text">DREAMS</div>
    <div class="text">DREAMS</div>
    <div class="text">DREAMS</div>
    <div class="text">DREAMS</div>
    <div class="text">DREAMS</div>
    <div class="text">DREAMS</div>
    <div class="text">DREAMS</div>
    </div>
    @import url(//fonts.googleapis.com/css?family=Archivo+Black);
    body {
      display: flex;
      justify-content: center;
      align-items: center;
      flex-direction: column;
      background-color: #7427FF;
      height: 100vh;
      width: 100vw;
    }
    .box {
      height: 550px;
      width: 550px;
      position: relative;
      overflow: hidden;
      text-align: center;
      filter: url(#noise); 
   // mask: url(#effect);
    }
    .svg {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translateY(-50%) translateX(-50%);
    z-index: 10;
    }

.text {
  font-family: 'Archivo Black', sans-serif;
  display: inline-block;
  font-size: 116px;
  line-height: 90px;
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  z-index: 0;
  background: linear-gradient(0deg, rgba(117,62,255,1) 0%, 
   rgba(249,37,166,1) 40%, rgba(246,154,180,1) 100%);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  animation-name: translate;
  animation-timing-function: linear;
  animation-duration: 10s;
  animation-iteration-count: infinite;
  animation-fill-mode: backwards;

@for $i from 1 through 16 {
    &:nth-child(#{$i}) {
      animation-delay:  #{$i * 1}s
    }
  }
}

@keyframes translate {
  from {
     transform: translateY(-90px) translateZ(0)
  }
  to {
      transform: translateY(555px) translateZ(0)
  }
}

1 Ответ

0 голосов
/ 07 июня 2019

Да, это возможно. Узнайте, как работает feDisplacementMap.

https://www.w3.org/TR/SVG11/single-page.html#filters-feDisplacementMapElement

Все, что вам нужно сделать, это убедиться, что пиксели вне круга вызывают смещение 0. Для этого значение цветового канала должно быть 0,5 (128).

Таким образом, если ваш X-канал является красным каналом, а Y-канал - зеленым, то создание области за пределами круга на 50% желтого цвета (т. Е. # 808000) должно привести к нулевому смещению.

Обновление: как работает feDisplacementMap

Принцип работы feDisplacement заключается в том, что он берет значение пикселя из «карты смещения» (in2) и использует цветовые каналы этого пикселя для определения местоположения в другом месте на верхнем изображении in, с которого копируется пиксель.

Так, например, скажем, мы в настоящее время смотрим на пиксель (100 200).

  • Посмотрите на пиксель в (100,200) в in2
  • Определить смещение смещения. Допустим, это (-0,4, 0,5). Мы увидим, как мы получим эти значения позже.
  • Умножьте смещение на scale. Если масштаб 10, новое смещение будет (-4, 5)
  • Получить пиксель в (100 - 4, 200 - 5) в in
  • Запишите это значение пикселя в (100,200) на выходе (result).

Разработка смещения

Начните с просмотра соответствующего цветового канала (R, G, B или A) в пикселе in2. Цветовой канал, который используется для смещений X и Y, устанавливается с помощью атрибутов xChannelSelector и yChannelSelector.

Каждый из этих каналов может иметь значение от 0 до 255. Для канала R 0 означает отсутствие красного, а 255 означает полный красный. Для расчета смещения вне диапазона 0..255 преобразуется в диапазон 0..1.

+----------------------+------+------------+
| Colour channel value | XC() | XC() - 0.5 |
+----------------------+------+------------+
|        0  (00)       |  0   |    -0.5    |
|       26  (1A)       |  0.1 |    -0.4    |
|      128  (80)       |  0.5 |     0      |
|      255  (FF)       |  1   |     0.5    |
+----------------------+------+------------+

Так что если xChannelSelector="R" и yChannelSelector="G", то значение пикселя #1AFF00 в нашем in2 приведет к смещению смещения (-0,4, 0,5), которое мы использовали выше.

Вернуться к картам смещения определенной формы

Из вышесказанного, мы надеемся, вы увидите, что, если канал пикселя in2 имеет значение 128, это приведет к смещению нуля. Это означает, что выходной пиксель в result будет скопирован непосредственно из той же позиции на входе (in).

Итак, чтобы создать карту с круговой границей. Все, что вам нужно сделать, это сделать все пиксели за пределами круга 128.

Проблема с feDisplacementMap

Изменения, произошедшие за последние пару лет с целью предотвращения некоторых проблем безопасности, связанных с feDisplacementMap, привели к тому, что его может быть довольно сложно использовать прямо сейчас. В этом процессе еще остались ошибки. Например: https://bugs.chromium.org/p/chromium/issues/detail?id=798001

Плюс есть ошибки с feImage: например. https://bugzilla.mozilla.org/show_bug.cgi?id=455986

Скорее всего, вам потребуется использовать внешние образы с feImage и убедиться, что на вашем веб-сервере установлены правильные настройки CORS.

Альтернативно, использование URL-адресов данных с feImage, кажется, работает нормально. См. этот CodePen от @ enxaneta .

Надеюсь, это помогло.

...