Search code examples
reactjsanimationsvggeometrygsap

How to add a border to an image inside an SVG circle


I am animating a stroke around a circle using GSAP. Here's a Codepen.

What I want to do is have spacing between the outer pink and (what should be) the inner circular image, like this:

enter image description here

Here's my SVG code:

      <svg id='svg1' width='48' height='48' viewBox='0 0 48 48'>
        <defs>
          <clipPath id='circleView'>
            <circle cx='24' cy='24' r='22' fill='none' stroke='#FF62E1' strokeWidth='2' />
          </clipPath>
        </defs>
        <image
          width='100%'
          height='100%'
          xlinkHref={'https://source.unsplash.com/random'}
          clipPath='url(#circleView)'
          />
        <circle
          cx='24'
          cy='24'
          r='22'
          fill='none'
          stroke='#FF62E1'
          strokeWidth='2'
          strokeDasharray='100.48'
          strokeDashoffset='100.48'
          // @ts-ignore
          ref={(circle) => { this.circle = circle }} >
          >
        </circle>
      </svg>

I have played around with filter and using multiple circles to create the effect, but to no avail.

Any ideas on how to achieve this?


Solution

  • You could change the radius on your clipPath circle to be a little bit less than the other circle and use a square image so it fits perfectly.

    render() {
      return (
        <svg id='svg1'  viewBox='0 0 48 48'>
          <defs>
            <clipPath id='circleView'>
              <circle cx='24' cy='24' r='18' fill='none' stroke='#FF62E1' strokeWidth='2' />
            </clipPath>
          </defs>
          <image
            x="0"
            y="0"
            width='48'
            height='48'
            xlinkHref={'https://source.unsplash.com/random/1500x1500/'}
            clipPath='url(#circleView)'
          />
          <circle
            cx='24'
            cy='24'
            r='22'
            fill='none'
            stroke='#FF62E1'
            strokeWidth='2'
            // @ts-ignore
            ref={(circle) => { this.circle = circle }} >
          </circle>
        </svg>
        )
      }
    }
    

    Codepen

    This option leaves a transparent gap where the background can be seen, so may or may not be exactly what you want. The alternative is to create another circle with a stroke but no fill on top with a different radius again.

    Alternative Codepen