Как я могу частично заполнить как положительное, так и отрицательное пространство в фигуре SVG?

Я хочу заполнить прогресс SVG двумя разными цветами

SVG код:

--

path d="M129.309 26.342C129.201 22.884 128.659 22.009 125.904 19.457C112.662 7.974 95.397 1 76.491 1C34.797 1 1 34.8 1 76.494C1 118.184 34.797 151.982 76.491 151.982C95.409 151.982 112.68 145.002 125.928 133.503C129.087 130.575 129.316 129.86 129.334 124.839L129.335 79.82L85.241 116.82C76.966 123.516 64.149 123.245 56.409 114.268C48.67 105.293 50.122 92.101 58.808 84.822C58.889 84.753 68.674 76.542 68.741 76.485C68.675 76.43 58.889 68.222 58.808 68.15C50.122 60.872 48.669 47.677 56.409 38.7C64.149 29.729 76.966 29.457 85.241 36.15L129.335 73.153V26.342H129.309Z" stroke="#27348B" stroke-width="2" stroke-miterlimit="10"

--

enter image description here

Свободный перевод вопроса How can I partially fill both positive and negative space in an SVG shape? от участника @Mathilde.


Ответы (2 шт):

Автор решения: Alexandr_TT

Я разделяю основной контур фона (#b9) и сердца (#h) на два пути. Я повторно использую основу и обрезаю элемент использования (use). Я заполняю и базовый, и используемый элемент одним и тем же градиентом. Также у элемента Use есть фильтр, который меняет синий цвет на красный.

svg{border:solid; width:200px}
<svg viewBox="0 0 135 152">
<defs>  
<filter id="b2r">
    <feColorMatrix in="SourceGraphic" type="matrix" values="0 0 1 0 0
       0 1 0 0 0
       1 0 0 0 0
       0 0 0 1 0"></feColorMatrix>
  </filter>
  
<linearGradient id="lg">
   <stop offset="0" stop-color="blue"></stop>
   <stop offset="0" stop-color="blue">
     <animate 
       attributeName="offset"
       attributeType="XML"
       from="0" to="1"
       dur="5s"
       repeatCount="indefinite"/>
   </stop>
  <stop offset="0" stop-color="transparent"></stop>
   <stop offset="1" stop-color="transparent"></stop>
  </linearGradient> 
<clipPath   id="cp">
  <path id="h" d="M129.334 124.839L129.335 79.82L85.241 116.82C76.966 123.516 64.149 123.245 56.409 114.268C48.67 105.293 50.122 92.101 58.808 84.822C58.889 84.753 68.674 76.542 68.741 76.485C68.675 76.43 58.889 68.222 58.808 68.15C50.122 60.872 48.669 47.677 56.409 38.7C64.149 29.729 76.966 29.457 85.241 36.15L129.335 73.153V26.342H129.309Z"  />
 />
  </clipPath>
  </defs>
<g fill="url(#lg)">  
<path id="b" d="M129.309 26.342C129.201 22.884 128.659 22.009 125.904 19.457C112.662 7.974 95.397 1 76.491 1C34.797 1 1 34.8 1 76.494C1 118.184 34.797 151.982 76.491 151.982C95.409 151.982 112.68 145.002 125.928 133.503C129.087 130.575 129.316 129.86 129.334 124.839z" stroke="blue" stroke-width="2" stroke-miterlimit="10" /> 
  
<use xlink:href="#b" filter="url(#b2r)" clip-path="url(#cp)" />  
</svg>

Свободный перевод ответа от участника @enxaneta.

→ Ссылка
Автор решения: Alexandr_TT

Что ж, сначала вам нужно выделить внутреннюю фигуру как новую фигуру, которую вы рисуете первой - вы не можете заполнить отрицательное пространство в SVG. И затем вам нужно создать два градиента, которые определены в терминах пользовательской области рисования (userSpaceOnUse), а не по умолчанию в процентах заполненной формы. Как только вы это сделаете, вы можете контролировать процент заливки, сделав средние точки градиента одинаковыми для обеих заливок.

<svg width="200px" height="200px" viewBox="0 0 200 200">
  <defs>
    <linearGradient id="inner" gradientUnits="userSpaceOnUse" x1="0" y1="0" x2="205" y2="0">
      <stop offset="0%"  stop-color="white" />
      <stop offset="0%"  stop-color="red" />
      <stop offset="40%"  stop-color="red" />
      <stop offset="40%" stop-color="white" />
      <stop offset="100%" stop-color="white" />
    </linearGradient>
    
     <linearGradient id="outer" gradientUnits="userSpaceOnUse" x1="0" y1="0" x2="205" y2="0">
      <stop offset="0%"  stop-color="white" />
      <stop offset="0%"  stop-color="#22D" />
      <stop offset="40%"  stop-color="#22D" />
      <stop offset="40%" stop-color="white" />
      <stop offset="100%" stop-color="white" />
    </linearGradient>
  </defs>
  
<path d="
M130.309 73.342 
L130.335 79.82
h -1          
L85.241 116.82
C76.966 123.516 64.149 123.245 56.409 114.268 
         
C48.67 105.293 50.122 92.101 58.808 84.822
C58.889 84.753 68.674 76.542 68.741 76.485
C68.675 76.43 58.889 68.222 58.808 68.15 
C50.122 60.872 48.669 47.677 56.409 38.7
C64.149 29.729 76.966 29.457 85.241 36.15 
L129.335 73.153" 
stroke="none" stroke-width="2" stroke-miterlimit="10" fill="url(#inner)" />  
  
  
<path d="M129.309 26.342C129.201 22.884 128.659 22.009 125.904 19.457C112.662 7.974 95.397 1 76.491 1C34.797 1 1 34.8 1 76.494C1 118.184 34.797 151.982 76.491 151.982C95.409 151.982 112.68 145.002 125.928 133.503C129.087 130.575 129.316 129.86 129.334 124.839L129.335 79.82L85.241 116.82C76.966 123.516 64.149 123.245 56.409 114.268C48.67 105.293 50.122 92.101 58.808 84.822C58.889 84.753 68.674 76.542 68.741 76.485C68.675 76.43 58.889 68.222 58.808 68.15C50.122 60.872 48.669 47.677 56.409 38.7C64.149 29.729 76.966 29.457 85.241 36.15L129.335 73.153V26.342H129.309Z" stroke="#27348B" stroke-width="2" stroke-miterlimit="10" fill="url(#outer)"/>

</svg>

<svg width="200px" height="200px" viewBox="0 0 200 200">
  <defs>
    <linearGradient id="inner" gradientUnits="userSpaceOnUse" x1="0" y1="0" x2="205" y2="0">
      <stop offset="0%"  stop-color="white" />
      <stop offset="0%"  stop-color="red" />
      <stop offset="55%"  stop-color="red" />
      <stop offset="55%" stop-color="white" />
      <stop offset="100%" stop-color="white" />
    </linearGradient>
    
     <linearGradient id="outer" gradientUnits="userSpaceOnUse" x1="0" y1="0" x2="205" y2="0">
      <stop offset="0%"  stop-color="white" />
      <stop offset="0%"  stop-color="#22D" />
      <stop offset="55%"  stop-color="#22D" />
      <stop offset="55%" stop-color="white" />
      <stop offset="100%" stop-color="white" />
    </linearGradient>
  </defs>
  
<path d="
M130.309 73.342 
L130.335 79.82
h -1          
L85.241 116.82
C76.966 123.516 64.149 123.245 56.409 114.268 
         
C48.67 105.293 50.122 92.101 58.808 84.822
C58.889 84.753 68.674 76.542 68.741 76.485
C68.675 76.43 58.889 68.222 58.808 68.15 
C50.122 60.872 48.669 47.677 56.409 38.7
C64.149 29.729 76.966 29.457 85.241 36.15 
L129.335 73.153" 
stroke="none" stroke-width="2" stroke-miterlimit="10" fill="url(#inner)" />  
  
  
<path d="M129.309 26.342C129.201 22.884 128.659 22.009 125.904 19.457C112.662 7.974 95.397 1 76.491 1C34.797 1 1 34.8 1 76.494C1 118.184 34.797 151.982 76.491 151.982C95.409 151.982 112.68 145.002 125.928 133.503C129.087 130.575 129.316 129.86 129.334 124.839L129.335 79.82L85.241 116.82C76.966 123.516 64.149 123.245 56.409 114.268C48.67 105.293 50.122 92.101 58.808 84.822C58.889 84.753 68.674 76.542 68.741 76.485C68.675 76.43 58.889 68.222 58.808 68.15C50.122 60.872 48.669 47.677 56.409 38.7C64.149 29.729 76.966 29.457 85.241 36.15L129.335 73.153V26.342H129.309Z" stroke="#27348B" stroke-width="2" stroke-miterlimit="10" fill="url(#outer)"/>

</svg>

Свободный перевод ответа от участника @Michael Mullany.

→ Ссылка