4

<svg id="color-gradient" width="400" height="400" version="1.1" xmlns="http://www.w3.org/2000/svg">
  <defs>
      <linearGradient id="gradient" x1="0" x2="0" y1="0" y2="1">
        <stop offset="0%" stop-color="red"/>
        <stop offset="50%" stop-color="blue" />
        <stop offset="100%" stop-color="yellow"/>
      </linearGradient>
  </defs>
    <circle cx="200" cy="200" r="100" fill="url(#gradient)"/>
</svg>

I want to create a svg gradient in a circle that has 3 points of color, set out in a triangle like this.

https://ibb.co/v3kMMqw

<svg id="color-gradient" width="400" height="400" version="1.1" xmlns="http://www.w3.org/2000/svg">
  <defs>
      <linearGradient id="gradient" x1="0" x2="0" y1="0" y2="1">
        <stop offset="0%" stop-color="red"/>
        <stop offset="50%" stop-color="blue" />
        <stop offset="100%" stop-color="yellow"/>
      </linearGradient>
  </defs>
    <circle cx="200" cy="200" r="100" fill="url(#gradient)"/>
</svg>

I have tried creating a linear Gradient with three stops, but I am not sure how to position the stops where I need them (top left right).

Gareth Jones
  • 871
  • 1
  • 7
  • 12

3 Answers3

7

This is about as close as you can get.

svg {
  width: 400px;
}
<svg viewBox="0 0 100 100">
  <defs>
    <filter id="blur" color-interpolation-filters="linear" x="-50%" y="-50%" width="200%" height="200%">
      <feGaussianBlur in="SourceGraphic" stdDeviation="9"/>
    </filter>
    <mask id="circle">
      <circle cx="50" cy="50" r="50" fill="white"/>
    </mask>
  </defs>
  <g mask="url(#circle)" filter="url(#blur)">
    <rect x="-10" width="110" height="110" fill="blue"/>
    <rect x="50" width="60" height="110" fill="yellow"/>
    <polygon points="50,50, 60,110, 40,110" fill="#0f8"/>
    <polygon points="0,0, 100,0, 100,20, 50,50, 0,20" fill="red"/>
    <polygon points="0,10, 50,50, 0,30" fill="#f0f"/>
    <polygon points="100,10, 100,30, 50,50" fill="#f80"/>
  </g>
  
</svg>

Since the blending you get in CSS/SVG works purely by combining the red, green, and blue channels of RGB colours separately, it doesn't know that we expect to see green when we blend blue and yellow. Instead you just get a murky grey.

So in the example above, I "cheated" by adding slivers of the "correct" colours in between our three main colours. For example I put a sliver of green between the blue and yellow sectors.

If I don't do that, the above example would look like this:

svg {
  width: 400px;
}
<svg viewBox="0 0 100 100">
  <defs>
    <filter id="blur" color-interpolation-filters="linear" x="-50%" y="-50%" width="200%" height="200%">
      <feGaussianBlur in="SourceGraphic" stdDeviation="7"/>
    </filter>
    <mask id="circle">
      <circle cx="50" cy="50" r="50" fill="white"/>
    </mask>
  </defs>
  <g mask="url(#circle)" filter="url(#blur)">
    <rect x="-10" width="110" height="110" fill="blue"/>
    <rect x="50" width="60" height="110" fill="yellow"/>
    <polygon points="0,0, 100,0, 100,20, 50,50, 0,20" fill="red"/>
  </g>
  
</svg>
Paul LeBeau
  • 97,474
  • 9
  • 154
  • 181
5

This topic is inspired by the answer @Paul LeBeau

The author of the question did not ask a question on animation. But I think that the options will be useful to someone.

  1. Gradient rotation

An animation command is added for a group of elements:

circle cx="50" cy="50" r="5" fill="white" stroke="silver">
     <animateTransform attributeName="transform" type="rotate" xlink:href="#gr1" dur="2s" values="0 50 50;360   50 50" repeatcount="indefinite"/>
   </circle>    

<style>
svg {
  width: 400px;
}
</style>
<svg viewBox="0 0 100 100">
  <defs>
    <filter id="blur" color-interpolation-filters="linear" x="-50%" y="-50%" width="200%" height="200%">
      <feGaussianBlur in="SourceGraphic" stdDeviation="10"/>
    </filter> 
    <mask id="circle">
      <circle cx="50" cy="50" r="50" fill="white">
   
    </circle>
    </mask>
  </defs>
  <g id="gr1" mask="url(#circle)" filter="url(#blur)">
    <rect x="-10" width="110" height="110" fill="blue"/>
    <rect x="50" width="60" height="110" fill="yellow"/>
    <polygon points="50,50, 60,110, 40,110" fill="#0f8"/>
    <polygon points="0,0, 100,0, 100,20, 50,50, 0,20" fill="red"/>
    <polygon points="0,10, 50,50, 0,30" fill="#f0f"/>
    <polygon points="100,10, 100,30, 50,50" fill="#f80"/>
  </g>
   <circle cx="50" cy="50" r="5" fill="white" stroke="silver">
     <animateTransform attributeName="transform" type="rotate" xlink:href="#gr1" dur="2s" values="0 50 50;360   50 50" repeatcount="indefinite"/>
   </circle>  
   
   </svg>
  1. Animation tracks

The command of animation of the radius of circles is added.

<circle cx="50" cy="50" r="5" fill="none" stroke-width="0.25" stroke="gray" >
     <animate id="an1" attributeName="r" values="5;50" dur="2s" begin="0s" repeatcount="indefinite" />
    </circle> 

<style>
svg {
  width: 400px;
}
</style>
<svg viewBox="0 0 100 100">
  <defs>
    <filter id="blur" color-interpolation-filters="linear" x="-50%" y="-50%" width="200%" height="200%">
      <feGaussianBlur in="SourceGraphic" stdDeviation="10"/>
    </filter> 
    <mask id="circle">
      <circle cx="50" cy="50" r="50" fill="white">
     </circle>
    </mask>
  </defs>
  <g id="gr1" mask="url(#circle)" filter="url(#blur)">
    <rect x="-10" width="110" height="110" fill="blue"/>
    <rect x="50" width="60" height="110" fill="yellow"/>
    <polygon points="50,50, 60,110, 40,110" fill="#0f8"/>
    <polygon points="0,0, 100,0, 100,20, 50,50, 0,20" fill="red"/>
    <polygon points="0,10, 50,50, 0,30" fill="#f0f"/>
    <polygon points="100,10, 100,30, 50,50" fill="#f80"/>
  </g>
   <circle cx="50" cy="50" r="5" fill="white" stroke="silver">
     <animateTransform attributeName="transform" type="rotate" xlink:href="#gr1" dur="2s" values="0 50 50;360   50 50" repeatcount="indefinite"/>
   </circle>  
   <circle cx="50" cy="50" r="5" fill="none" stroke-width="0.25" stroke="gray" >
     <animate id="an1" attributeName="r" values="5;50" dur="2s" begin="0s" repeatcount="indefinite" />
 </circle> 
  <circle cx="50" cy="50" r="5" fill="none" stroke-width="0.25" stroke="gray" >
     <animate id="an2" attributeName="r" values="5;50" dur="2s" begin="0.5s" repeatcount="indefinite" />
   </circle> 
   <circle cx="50" cy="50" r="5" fill="none" stroke-width="0.25" stroke="gray" >
     <animate id="an3" attributeName="r" values="5;50" dur="2s" begin="1s" repeatcount="indefinite" />
   </circle> 
     <circle cx="50" cy="50" r="5" fill="none" stroke-width="0.25" stroke="gray" >
     <animate id="an3" attributeName="r" values="5;50" dur="2s" begin="1.5s" repeatcount="indefinite" />
   </circle> 
 <circle cx="50" cy="50" r="5" fill="none" stroke-width="0.25" stroke="gray" >
     <animate id="an3" attributeName="r" values="5;50" dur="2s" begin="2s" repeatcount="indefinite" />
   </circle>  
   </svg>
Alexandr_TT
  • 13,635
  • 3
  • 27
  • 54
1

i wanted to give it a try, too.

the result is very different depending on the browser, firefox for example doesn't produce a very good result. (although that is also true for the other solutions, I think)

but it doesn't need the manually inserted composite colors and produces a very homogeneous effect on Safari and Chrome…

<svg viewBox="0 0 100 100">
    <defs>
        <filter id="colorblend">
            <feColorMatrix in="SourceGraphic" result="red" type="matrix" values="
            1 0 0 0 0
            0 0 0 0 0
            0 0 0 0 0
            1 0 0 0 0" />
            <feColorMatrix in="SourceGraphic" result="green" type="matrix" values="
            0 0 0 0 0
            0 1 0 0 0
            0 0 0 0 0
            0 1 0 0 0" />
            <feColorMatrix in="SourceGraphic" result="blue" type="matrix" values="
            0 0 0 0 0
            0 0 0 0 0
            0 0 1 0 0
            0 0 1 0 0" />

            <feGaussianBlur in="red" stdDeviation="20" result="red" />
            <feGaussianBlur in="green" stdDeviation="20" result="green" />
            <feGaussianBlur in="blue" stdDeviation="20" result="blue" />

            <feBlend mode="screen" in="red" in2="green" result="redplusgreen" />
            <feBlend mode="screen" in="redplusgreen" in2="blue" result="rainbow" />

            <!--fix alpha -->
            <feColorMatrix in="rainbow" result="rainbow" type="matrix" values="
            1 0 0 0 0
            0 1 0 0 0
            0 0 1 0 0
            0 0 0 20 0" />

            <!-- increase brightness -->
            <feBlend in="rainbow" in2="rainbow" mode="screen" result="rainbow" />

            <!-- remove artefacts -->
            <feGaussianBlur in="rainbow" stdDeviation="1" />
        </filter>

        <mask id="mask">
            <circle cx="50" cy="50" r="50" fill="white"></circle>
        </mask>
    </defs>
    <g mask="url(#mask)" filter="url(#colorblend)">
        <rect x="-10" width="110" height="110" fill="red" />
        <rect x="50" width="60" height="110" fill="lime" />
        <polygon points="0,0, 100,0, 100,30, 50,50, 0,30" fill="blue" />
    </g>
</svg>