Прости мой английский
Я использую 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>Как видите, изображение сдвинуто. Если вы проверите код, блоки не будут соответствовать видимому изображению:
Вот с добавлением интерактивности:
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? Например, используя холст, спасибо!



Поведение при размещении изображения, которое вы видите, связано с тем, что элементы <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>