Search code examples
svgdonut-chart

SVG donut slice changing color on hover


I have a simple SVG donut with 5 equal slices placed using stroke-dashoffset="xx". The donut itself looks OK but when I try to add some hover changes to each slice, for example, simple changing of the stroke color:

donut-piece:hover {
  stroke: #fc7822;
}

It doesn't work very well since all circles are basically on top of each other. Is there a way to make it work as expected?

Here is the donut code:

.donut-piece:hover {
  stroke: #fc7822;
}
<svg width="700" viewBox="0 0 42 42" class="donut">
   <circle class="donut-hole" cx="21" cy="21" r="15.91549430918954" fill="transparent"></circle>
   <circle class="donut-ring" cx="21" cy="21" r="15.91549430918954" fill="transparent" stroke="transparent" stroke-width="10"></circle>

   <circle class="donut-data donut-piece" cx="21" cy="21" r="15.91549430918954" fill="transparent" stroke="#535f7f" stroke-width="10" stroke-dasharray="15 85" stroke-dashoffset="3"></circle>
   <circle class="donut-device donut-piece" cx="21" cy="21" r="15.91549430918954" fill="transparent" stroke="#556180" stroke-width="10" stroke-dasharray="15 85" stroke-dashoffset="18"></circle>
   <circle class="donut-physical donut-piece" cx="21" cy="21" r="15.91549430918954" fill="transparent" stroke="#51628f" stroke-width="10" stroke-dasharray="15 85" stroke-dashoffset="33"></circle>
   <circle class="donut-network donut-piece" cx="21" cy="21" r="15.91549430918954" fill="transparent" stroke="#556180" stroke-width="10" stroke-dasharray="15 85" stroke-dashoffset="48"></circle>
   <circle class="donut-iot donut-piece" cx="21" cy="21" r="15.91549430918954" fill="transparent" stroke="#535f7f" stroke-width="10" stroke-dasharray="15 85" stroke-dashoffset="63"></circle>

</svg>


Solution

  • The browser is highlighting the correct segment when you are outside the radius of the circle. However when the pointer is inside the circle radius, the browser thinks you are hovering over the bottom-left segment. This corresponds to the last circle in your SVG file.

    You are getting this effect because you have set the fill of your circles to transparent. SVG's hover testing will only ignore a fill or a stroke when it is set to none. They are not treated as being equivalent.

    There are two ways to solve your problem:

    1. Change the fill colour of your circles to "none"

    .donut-piece:hover {
      stroke: #fc7822;
    }
    <svg width="700" viewBox="0 0 42 42" class="donut">
       <circle class="donut-hole" cx="21" cy="21" r="15.91549430918954" fill="transparent"></circle>
       <circle class="donut-ring" cx="21" cy="21" r="15.91549430918954" fill="transparent" stroke="transparent" stroke-width="10"></circle>
    
       <circle class="donut-data donut-piece" cx="21" cy="21" r="15.91549430918954" fill="none" stroke="#535f7f" stroke-width="10" stroke-dasharray="15 85" stroke-dashoffset="3"></circle>
       <circle class="donut-device donut-piece" cx="21" cy="21" r="15.91549430918954" fill="none" stroke="#556180" stroke-width="10" stroke-dasharray="15 85" stroke-dashoffset="18"></circle>
       <circle class="donut-physical donut-piece" cx="21" cy="21" r="15.91549430918954" fill="none" stroke="#51628f" stroke-width="10" stroke-dasharray="15 85" stroke-dashoffset="33"></circle>
       <circle class="donut-network donut-piece" cx="21" cy="21" r="15.91549430918954" fill="none" stroke="#556180" stroke-width="10" stroke-dasharray="15 85" stroke-dashoffset="48"></circle>
       <circle class="donut-iot donut-piece" cx="21" cy="21" r="15.91549430918954" fill="none" stroke="#535f7f" stroke-width="10" stroke-dasharray="15 85" stroke-dashoffset="63"></circle>
    
    </svg>

    2. Tell the browser to ignore the fill for mouse events

    You can do that by setting pointer-events: visibleStroke;. The default value for pointer-events is visiblePainted, which tests for both the fill and the stroke.

    You can read more about pointer-events here.

    .donut-piece {
      pointer-events: visibleStroke;
    }
    
    .donut-piece:hover {
      stroke: #fc7822;
    }
    <svg width="700" viewBox="0 0 42 42" class="donut">
       <circle class="donut-hole" cx="21" cy="21" r="15.91549430918954" fill="transparent"></circle>
       <circle class="donut-ring" cx="21" cy="21" r="15.91549430918954" fill="transparent" stroke="transparent" stroke-width="10"></circle>
    
       <circle class="donut-data donut-piece" cx="21" cy="21" r="15.91549430918954" fill="transparent" stroke="#535f7f" stroke-width="10" stroke-dasharray="15 85" stroke-dashoffset="3"></circle>
       <circle class="donut-device donut-piece" cx="21" cy="21" r="15.91549430918954" fill="transparent" stroke="#556180" stroke-width="10" stroke-dasharray="15 85" stroke-dashoffset="18"></circle>
       <circle class="donut-physical donut-piece" cx="21" cy="21" r="15.91549430918954" fill="transparent" stroke="#51628f" stroke-width="10" stroke-dasharray="15 85" stroke-dashoffset="33"></circle>
       <circle class="donut-network donut-piece" cx="21" cy="21" r="15.91549430918954" fill="transparent" stroke="#556180" stroke-width="10" stroke-dasharray="15 85" stroke-dashoffset="48"></circle>
       <circle class="donut-iot donut-piece" cx="21" cy="21" r="15.91549430918954" fill="transparent" stroke="#535f7f" stroke-width="10" stroke-dasharray="15 85" stroke-dashoffset="63"></circle>
    
    </svg>