简体   繁体   中英

SVG: Apply fill color to “masked” image on hover

I'm using clipPath to apply different "masking" effects to an image.

How can I fill the clipped image with a color on hover? I've tried using :hover in CSS, but that didn't seem to work, unless I was targeting the incorrect element.

I'm using jQuery in this project, so if a JS solution is needed, I can lean on jQuery.

Here's the HTML that I'm working with:

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 100 100">
  <defs>
    <clipPath id="ellipse">
      <ellipse cx="50" cy="35.5" rx="49.5" ry="35" />
    </clipPath>
    <clipPath id="hexagon">
      <polygon points="25, 0  75, 0 100, 43.30127018922193 75, 86.60254037844386  25, 86.60254037844386  0, 43.30127018922193"/>
    </clipPath>
    <clipPath id="rectangle">
      <rect x="0" y="0" width="100" height="70"></rect>
    </clipPath>
  </defs>
  <g>
    <image preserveAspectRatio="none" x="0" y="0" width="100%" height="100%" xlink:href="http://upload.wikimedia.org/wikipedia/commons/thumb/b/bf/Bucephala-albeola-010.jpg/800px-Bucephala-albeola-010.jpg" id="clippy" clip-path="url(#hexagon)">
  </g>
</svg>

You might want to use a filter effect for giving the image some color on hover ( see Tinkerbin ):

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 100 100">
  <style type="text/css">
    image:hover {
      filter:url(#Matrix);
    }
  </style>
  <defs>
    <clipPath id="ellipse">
      <ellipse cx="50" cy="35.5" rx="49.5" ry="35" />
    </clipPath>
    <clipPath id="hexagon">
      <polygon points="25, 0  75, 0 100, 43.30127018922193 75, 86.60254037844386  25, 86.60254037844386  0, 43.30127018922193"/>
    </clipPath>
    <clipPath id="rectangle">
      <rect x="0" y="0" width="100" height="70"></rect>
    </clipPath>
    <filter id="Matrix" filterUnits="objectBoundingBox" 
            x="0%" y="0%" width="100%" height="100%">
      <feColorMatrix type="matrix" in="SourceGraphic"
           values="1 0 0 0 .5 
                   .1 .9 0 0 0 
                   .1 0 .9 0 0 
                   0 0 0 1 0"/>
    </filter>
  </defs>
  <g>
    <image preserveAspectRatio="none" x="0" y="0" width="100%" height="100%" xlink:href="http://upload.wikimedia.org/wikipedia/commons/thumb/b/bf/Bucephala-albeola-010.jpg/800px-Bucephala-albeola-010.jpg" id="clippy" clip-path="url(#hexagon)">
  </g>
</svg>

Edit: Some explanation about the filter:

The applied filter changes the color of every rastered pixel. It takes its original color value, applies the matrix specified by <feColorMatrix> to the color vector, and the resulting color vector becomes the displayed color.

How does the matrix work?

The matrix consists of four rows. The first row calculates the new red component, the second the green one, third blue, fourth alpha.

What's the meaning of the five numbers in each row? The first number is multiplied by the original color's red component, the second by the green one, third blue, fourth alpha. All four products are summed up, and the fifth value in the row is added as well (as a constant that does not depend on any of the original color components).

Let's have a look at the above example: Let's assume we have a grey pixel with color values like

rgba(25%,25%,25%,1)

What would be the resulting red value? The first row that calculates the red value is

1 0 0 0 .5

We calculate the following:

  1*r   + 0*g   + 0*b   + 0*a + .5
= 1*.25 + 0*.25 + 0*.25 + 0*1 + .5 = .75

This means, the resulting red component for the pixel is 75%. The other components are calculated analogously.

Not sure if this is exactly what you want. Mouse events aren't sent to areas outside a cliparea. Quick & dirty, works in IE9, haven't tested in FF for example.

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 100 100">
    <script type="application/ecmascript">
        function fillit(evt) {
            document.getElementById('fillarea').setAttribute('display', 'visible');
        }

        function emptyit(evt) {
            document.getElementById('fillarea').setAttribute('display', 'none');
        }
    </script>
    <defs>
        <clipPath id="ellipse">
            <ellipse cx="50" cy="35.5" rx="49.5" ry="35" />
        </clipPath>
        <clipPath id="hexagon">
            <polygon points="25, 0  75, 0 100, 43.30127018922193 75, 86.60254037844386  25, 86.60254037844386  0, 43.30127018922193" />
        </clipPath>
        <clipPath id="rectangle">
            <rect x="0" y="0" width="100" height="70"></rect>
        </clipPath>
    </defs>
    <g>
        <image preserveAspectRatio="none" x="0" y="0" width="100%" height="100%" 
               xlink:href="http://upload.wikimedia.org/wikipedia/commons/thumb/b/bf/Bucephala-albeola-010.jpg/800px-Bucephala-albeola-010.jpg" 
               id="clippy" clip-path="url(#hexagon)" onmouseover="fillit(evt)" />
        <rect x="0" y="0" width="100%" height="100%" fill="red" display="none" 
              id="fillarea" clip-path="url(#hexagon)" onmouseout="emptyit(evt)" />
    </g>
</svg>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM