具有圆角的矩形元素的波纹效果SVG

时间:2021-03-22 12:25:35

标签: javascript html svg

我正在研究 SVG 中 click 的涟漪效应。涟漪效应的基本思想是每当用户点击 rect 标签时,就会根据点击的坐标和 rect 标签的尺寸创建一个圆形元素并进行动画处理。但是为了维持矩形内的圆,我使用了符号标签,它工作正常,但仅适用于没有 rx, ry 属性的矩形。主要问题是用圆角支撑矩形中的圆。

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Ripple</title>
  <style>
     :root {
      --radius: 0;
    }
    
    .ripple {
      animation: ripple 600ms linear;
    }
    
    @keyframes ripple {
      to {
        r: var(--radius);
        opacity: 0;
      }
    }
  </style>
</head>

<body>

  <svg id="svg" width="1300" height="500" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" focusable="false">
   
   

    <symbol  id="ripp" width="200" height="200">
        <rect rx="100" x="0" y="0"  id="rec"   width="200" height="200"
        style="fill:red;opacity:0.5"></rect>
      </symbol>

      <symbol x="60" y="260"  id="ripp2" width="200" height="50">
        <rect x="0" y="0"  id="rec2"   width="200" height="50"
        style="fill:red;opacity:0.5"></rect>
      </symbol>


      <use xlink:href="#ripp" ></use> 

      <use xlink:href="#ripp2" ></use> 
 
 </svg>
  <script>
    const svg = document.getElementById('svg');
    const rect = document.getElementById('rec');
    const rect2 = document.getElementById('rec2');


    setRipple(svg, rect, document.querySelector('#ripp'), 'red');
    setRipple(svg, rect2, document.querySelector('#ripp2'), 'white');

    function setRipple(svg, rect, symbolEle, color) {

      function getactualcoor(elem, X, Y) {

        let pt = elem.createSVGPoint();

        pt.x = X;
        pt.y = Y;

        return pt.matrixTransform(elem.getScreenCTM().inverse());
      }


      rect.addEventListener('click', clickHandler);


      function clickHandler(e) {

        let radiusVariable = document.querySelector(':root');

        let xminus = Number(symbolEle.getAttributeNS(null, 'x'));

        let yminus = Number(symbolEle.getAttributeNS(null, 'y'));



        let actualXminus = 0;
        let actualYminus = 0;

        if (xminus != null) {

          actualXminus = xminus;

        }

        if (yminus != null) {

          actualYminus = yminus;

        }

        let widthRect = rect.getBoundingClientRect().width;

        let heightRect = rect.getBoundingClientRect().height;

        let radiusAchieve = Math.sqrt(Math.pow(widthRect, 2) + Math.pow(heightRect, 2));


        radiusVariable.style.setProperty('--radius', radiusAchieve);

        let cooractual = getactualcoor(svg, e.clientX, e.clientY);

        let initial = symbolEle.getElementsByClassName("ripple")[0];


        if (initial) {
          initial.remove()
        }

        let circ = document.createElementNS('http://www.w3.org/2000/svg', 'circle');

        circ.setAttributeNS(null, 'cx', cooractual.x - actualXminus);
        circ.setAttributeNS(null, 'cy', cooractual.y - actualYminus);
        circ.style.pointerEvents = "none";
        circ.classList.add('ripple');
        circ.style.fill = color;


        symbolEle.appendChild(circ);

      }
    }
  </script>
</body>

</html>

1 个答案:

答案 0 :(得分:0)

使用<mask>

<!-- define the path -->
<defs>
    <rect rx="100" x="0" y="0"  id="path-rec"  width="200" height="200" />
</defs>
<!-- define the mask -->
<mask id="mask-rec" fill="white">
    <use xlink:href="#path-rec"></use>
</mask>
<symbol id="ripp" width="200" height="200">
    <g fill="red" opacity="0.5">
        <use xlink:href="#path-rec" id="rec" ></use>
    </g>
</symbol>

<!-- use the mask -->
<use xlink:href="#ripp" mask="url(#mask-rec)"></use> 

    <!DOCTYPE html>
    <html lang="en">

    <head>
      <meta charset="UTF-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Ripple</title>
      <style>
         :root {
          --radius: 0;
        }
        
        .ripple {
          animation: ripple 600ms linear;
        }
        
        @keyframes ripple {
          to {
            r: var(--radius);
            opacity: 0;
          }
        }
      </style>
    </head>

    <body>

      <svg id="svg" width="1300" height="500" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" focusable="false">
       
       
        <defs>
            <rect rx="100" x="0" y="0"  id="path-rec"  width="200" height="200" />
        </defs>
        <mask id="mask-rec" fill="white">
            <use xlink:href="#path-rec"></use>
        </mask>
        <symbol id="ripp" width="200" height="200">
            <g fill="red" opacity="0.5">
                <use xlink:href="#path-rec" id="rec" ></use>
            </g>
        </symbol>

          <symbol x="60" y="260"  id="ripp2" width="200" height="50">
            <rect x="0" y="0"  id="rec2"   width="200" height="50"
            style="fill:red;opacity:0.5"></rect>
          </symbol>


          <use xlink:href="#ripp" mask="url(#mask-rec)"></use> 

          <use xlink:href="#ripp2" ></use> 
     
     </svg>
      <script>
        const svg = document.getElementById('svg');
        const rect = document.getElementById('rec');
        const rect2 = document.getElementById('rec2');


        setRipple(svg, rect, document.querySelector('#ripp'), 'red');
        setRipple(svg, rect2, document.querySelector('#ripp2'), 'white');

        function setRipple(svg, rect, symbolEle, color) {

          function getactualcoor(elem, X, Y) {

            let pt = elem.createSVGPoint();

            pt.x = X;
            pt.y = Y;

            return pt.matrixTransform(elem.getScreenCTM().inverse());
          }


          rect.addEventListener('click', clickHandler);


          function clickHandler(e) {

            let radiusVariable = document.querySelector(':root');

            let xminus = Number(symbolEle.getAttributeNS(null, 'x'));

            let yminus = Number(symbolEle.getAttributeNS(null, 'y'));



            let actualXminus = 0;
            let actualYminus = 0;

            if (xminus != null) {

              actualXminus = xminus;

            }

            if (yminus != null) {

              actualYminus = yminus;

            }

            let widthRect = rect.getBoundingClientRect().width;

            let heightRect = rect.getBoundingClientRect().height;

            let radiusAchieve = Math.sqrt(Math.pow(widthRect, 2) + Math.pow(heightRect, 2));


            radiusVariable.style.setProperty('--radius', radiusAchieve);

            let cooractual = getactualcoor(svg, e.clientX, e.clientY);

            let initial = symbolEle.getElementsByClassName("ripple")[0];


            if (initial) {
              initial.remove()
            }

            let circ = document.createElementNS('http://www.w3.org/2000/svg', 'circle');

            circ.setAttributeNS(null, 'cx', cooractual.x - actualXminus);
            circ.setAttributeNS(null, 'cy', cooractual.y - actualYminus);
            circ.style.pointerEvents = "none";
            circ.classList.add('ripple');
            circ.style.fill = color;


            symbolEle.appendChild(circ);

          }
        }
      </script>
    </body>

    </html>