Как исключить фигуры в SVG или холсте?

Прости мой английский

Я использую svg с фильтрами, но столкнулся со следующей проблемой.

Это база для svg. Ожидаемый результат:

<svg xmlns = "http://www.w3.org/2000/svg" width = "100" height = "100" viewBox = "0 0 100 100">
  <g>
    <circle id = "2" cx = "50" cy = "50" r = "50"/>
    <g id = "1">
      <rect x = "0" y = "0" width = "50" height = "50" fill = "#ccc"/>
      <rect x = "50" y = "50" width = "50" height = "50" fill = "#ccc"/>
    </g>
  </g>
</svg>

А вот с фильтром feComposite:

<svg xmlns = "http://www.w3.org/2000/svg" width = "100" height = "100" viewBox = "0 0 100 100">

  <defs>
    <filter id = "myFilter1">
      <feImage href = "#1" result = "1"/>
      <feImage href = "#2" result = "2"/>
      <feComposite in = "1" in2 = "2" operator = "xor"/>
    </filter>
  </defs>
  
  <g filter = "url(#myFilter1)">
    <circle id = "2" cx = "50" cy = "50" r = "50"/>
    <g id = "1">
      <rect x = "0" y = "0" width = "50" height = "50" fill = "#ccc"/>
      <rect x = "50" y = "50" width = "50" height = "50" fill = "#ccc"/>
    </g>
  </g>
</svg>

Как видите, изображение сдвинуто. Если вы проверите код, блоки не будут соответствовать видимому изображению:

Как исключить фигуры в SVG или холсте?

Вот с добавлением интерактивности:

const value = (max = 100000000, min = 0) => Math.round(Math.random() * (max - min)) + min;

const createCircle = (size) => {
  const r = value(10, 3);
  const cx = value(size - r - 10, r + 10);
  const cy = value(size - r - 10, r + 10);
  return {
    r,
    cx,
    cy
  }
};

const createCircles = (counts, size) => Array(counts).fill().map(() => createCircle(size));


class App extends React.Component {

    constructor(props) {
      super(props);

      this.state = {
        position: {
          x: 0,
          y: 0,
        }
      };

      this.size = 300;

      this.circlesData = createCircles(100, this.size);

      const getCoords = (c, i) => c + (this.state.position.x * 0.002 * c * (i % 2 ? 1 : -1));

      this.circles = () => this.circlesData.map((item, i) => <circle key = {`circles_12dew1_${i}`} cx = {getCoords(item.cx, i)} cy = {getCoords(item.cy, i)} r = {item.r}/>);

    }

    onMouseMove = e => {
      const position = {
        x: e.pageX,
        y: e.pageY,
      };
      this.setState({position});
    }

    render() {
      return (
      <div className = "App" >
        <svg onMouseMove = {this.onMouseMove} ref = {elem => this.svg = elem} xmlns = "http://www.w3.org/2000/svg" width = {this.size} height = {this.size} viewBox = {`0 0 ${this.size} ${this.size}`}>
          
          <defs>
            <filter id = "myFilter1">
             <feImage href = "#1" result = "1"/>
             <feImage href = "#2" result = "2"/>
             <feComposite in  = "1" in2 = "2" operator = "xor"/>
            </filter>
 
          </defs>

          <g id = "3" filter = "url(#myFilter1)" >
            <circle id = "2" cx = {this.size / 2 + 100} cy = {this.size / 2 + 100} r = {this.size / 3}/>
            <g id = "1"> {this.circles()} </g> 
          </g>
        </svg> 
      </div>
    );
  }
}


ReactDOM.render( < App / > , document.getElementById('root'));
<div id = "root"></div>
<script src = "https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src = "https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

Как видите, большой круг движется, но этого не должно быть.

Как исправить?

Или как сделать исключение фигур как в интерактивном примере без svg? Например, используя холст, спасибо!

Создание фильтров для вашего сайта
Создание фильтров для вашего сайта
Фильтры - удобный инструмент в арсенале веб-дизайнера. Они позволяют изменять элементы на странице с помощью всего нескольких строк кода. Эти...
Анимация SVG-узоров без единой строки CSS
Анимация SVG-узоров без единой строки CSS
Недавно я работал над веб-проектом, который позволил мне поэкспериментировать с шаблонами SVG. С SVG очень приятно работать, как только вы получите...
Как использовать d3.js для рисования 2D SVG-элементов в приложении Angular?
Как использовать d3.js для рисования 2D SVG-элементов в приложении Angular?
D3.js - это обширная библиотека, используемая для привязки произвольных данных к объектной модели документа (DOM). Мы разберем основные варианты...
2
0
52
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Поведение при размещении изображения, которое вы видите, связано с тем, что элементы <feImage> позиционируются с использованием области фильтра или области примитива фильтра.

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

По умолчанию область фильтра - это область, которая со всех сторон на 10% больше исходного объекта.

x = "- 10%" y = "- 10%" width = "120%" height = "120%"

Это сделано для обслуживания примитивов фильтра, таких как <feGuassianBlur>, которые выходят за пределы исходного размера и в противном случае были бы обрезаны.

Чтобы изображения располагались так, как вы хотите, измените область фильтра или область примитива фильтра, чтобы она была того же размера, что и исходный объект. Например:

<feImage href = "#1" x = "0" y = "0" width = "100%" height = "100%" result = "1"/>

Обновленная демоверсия:

<svg xmlns = "http://www.w3.org/2000/svg" width = "100" height = "100" viewBox = "0 0 100 100">

  <defs>
    <filter id = "myFilter1">
      <feImage href = "#1" x = "0" y = "0" width = "100%" height = "100%" result = "1"/>
      <feImage href = "#2" x = "0" y = "0" width = "100%" height = "100%" result = "2"/>
      <feComposite in = "1" in2 = "2" operator = "xor"/>
    </filter>
  </defs>
  
  <g filter = "url(#myFilter1)">
    <circle id = "2" cx = "50" cy = "50" r = "50"/>
    <g id = "1">
      <rect x = "0" y = "0" width = "50" height = "50" fill = "#ccc"/>
      <rect x = "50" y = "50" width = "50" height = "50" fill = "#ccc"/>
    </g>
  </g>
</svg>

Другие вопросы по теме