如何排除SVG或画布中的形状?

时间:2018-10-26 05:36:26

标签: 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>

如您所见,图像已移动。如果您检查代码,则块将与可见图像不匹配:

enter image description here

在这里增加了交互性:

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的交互式示例中一样,如何使图形例外?例如使用画布,谢谢!

1 个答案:

答案 0 :(得分:4)

您看到的图像放置行为是因为<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>