Pure CSS3 or SVG animated Doughnut Chart - html

I am looking for a pure CSS3 or SVG animated doughnut chart.
Need to have the middle circle fill colour
the outer circle to be split with a grey and a blue ie: blue 80% complete, grey 20% left remaining.
need text in the middle of the circle.
I have found one example http://jsfiddle.net/4azpfk3r/
Can anyone help creating / editing the above to what i need please? Its half way there.
<div class="item css">
<h2>CSS</h2>
<svg width="160" height="160" xmlns="http://www.w3.org/2000/svg">
<g>
<title>Layer 1</title>
<circle id="circle" class="circle_animation" r="69.85699" cy="81" cx="81" stroke-width="8" stroke="#69aff4" fill="none"/>
</g>
</svg>
</div>
Thanks

Try this, it uses stroke-dasharray to create strokes with a length of 251.2 see here for more reference . The stroke-dashoffset attribute specifies the distance into the dash pattern to start the dash see here
<svg width="100%" height="100%" viewbox="0 0 100 100">
<circle cx="50" cy="50" r="40" fill="tomato"/>
<circle cx="50" cy="50" r="40" fill="transparent" stroke-width="20" stroke="grey"/>
<circle cx="50" cy="50" r="40" fill="transparent" stroke-width="20" stroke="#00CCFF" stroke-dasharray="251.2" stroke-dashoffset="50.3"/>
<text x="40" y="50" fill="black" font-size="10">Text</text>
</svg>
Here the stroke fills 80% (calculated using 251.2 - 251.2*80/100, 251.2 is the perimeter of the circle calculated using 2 * 3.14 * 40). ie stroke-dashoffset = perimeter - perimeter * amount / 100 also set stroke-dasharray to perimeter. perimeter = 2 * 3.14 * radius.
You can check this blog post that explains the creation of doughnut charts easily.
See a 50% filled circle
<svg width="100%" height="100%" viewbox="0 0 100 100">
<circle cx="50" cy="50" r="40" fill="tomato"/>
<circle cx="50" cy="50" r="40" fill="transparent" stroke-width="20" stroke="grey"/>
<circle cx="50" cy="50" r="40" fill="transparent" stroke-width="20" stroke="#00CCFF" stroke-dasharray="251.2" stroke-dashoffset="125.6"/>
<text x="40" y="50" fill="black" font-size="10">Text</text>
</svg>
Demo with multiple rings :
<svg width="300px" height="300px" viewbox="0 0 100 100">
<!-- Center color -->
<circle cx="50" cy="50" r="40" fill="#eee"/>
<!-- Default color of ring -->
<circle cx="50" cy="50" r="40" fill="transparent" stroke-width="20" stroke="grey"/>
<!-- Progress -->
<!-- The amount shown as 'filled' is the amount the ring fills, starting from right center (3 o' clock) -->
<!-- 100% fill -->
<circle cx="50" cy="50" r="40" fill="transparent" stroke-width="20" stroke="#2196f3" stroke-dasharray="251.2" stroke-dashoffset="0"/>
<!-- 80% fill -->
<circle cx="50" cy="50" r="40" fill="transparent" stroke-width="20" stroke="#ff5722" stroke-dasharray="251.2" stroke-dashoffset="50.3"/>
<!-- 70% filled -->
<circle cx="50" cy="50" r="40" fill="transparent" stroke-width="20" stroke="#009688" stroke-dasharray="251.2" stroke-dashoffset="75.36"/>
<!-- 50% filled -->
<circle cx="50" cy="50" r="40" fill="transparent" stroke-width="20" stroke="#9c27b0" stroke-dasharray="251.2" stroke-dashoffset="125.6"/>
<!-- 40% filled -->
<circle cx="50" cy="50" r="40" fill="transparent" stroke-width="20" stroke="#e91e63" stroke-dasharray="251.2" stroke-dashoffset="150.72"/>
<!-- 20% filled -->
<circle cx="50" cy="50" r="40" fill="transparent" stroke-width="20" stroke="#f44336" stroke-dasharray="251.2" stroke-dashoffset="200.96"/>
<!-- Center Text -->
<text x="40" y="50" fill="black" font-size="10">Text</text>
</svg>
Demo with animation (not tested in all browsers)
$(".progress").each(function() {
var dataProgress = $(this).attr("stroke-dashoffset");
$(this).attr("stroke-dashoffset", "251.2");
$(this).animate({
"stroke-dashoffset": dataProgress
},1500)
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<svg width="300px" height="300px" viewbox="0 0 100 100">
<!-- Center color -->
<circle cx="50" cy="50" r="40" fill="#eee"/>
<!-- Default color of ring -->
<circle cx="50" cy="50" r="40" fill="transparent" stroke-width="20" stroke="white"/>
<!-- Progress -->
<!-- The amount shown as 'filled' is the amount the ring fills, starting from right center (3 o' clock) -->
<!-- 100% fill -->
<circle class="progress" cx="50" cy="50" r="40" fill="transparent" stroke-width="20" stroke="#2196f3" stroke-dasharray="251.2" stroke-dashoffset="0"/>
<!-- 80% fill -->
<circle class="progress" cx="50" cy="50" r="40" fill="transparent" stroke-width="20" stroke="#ff5722" stroke-dasharray="251.2" stroke-dashoffset="50.3"/>
<!-- 70% filled -->
<circle class="progress" cx="50" cy="50" r="40" fill="transparent" stroke-width="20" stroke="#009688" stroke-dasharray="251.2" stroke-dashoffset="75.36"/>
<!-- 50% filled -->
<circle class="progress" cx="50" cy="50" r="40" fill="transparent" stroke-width="20" stroke="#9c27b0" stroke-dasharray="251.2" stroke-dashoffset="125.6"/>
<!-- 40% filled -->
<circle class="progress" cx="50" cy="50" r="40" fill="transparent" stroke-width="20" stroke="#e91e63" stroke-dasharray="251.2" stroke-dashoffset="150.72"/>
<!-- 20% filled -->
<circle class="progress" cx="50" cy="50" r="40" fill="transparent" stroke-width="20" stroke="#f44336" stroke-dasharray="251.2" stroke-dashoffset="200.96"/>
<!-- Center Text -->
<text x="40" y="50" fill="black" font-size="10">Text</text>
</svg>
Solution using jquery :
Give data-fill=amount to each of the .progress and jquery will do the rest
var radius = parseInt($("#radius").attr("r")) // Get the radius of the circle
var perimeter = 2 * 3.14 * radius;
$(".progress").each(function(){
var amount = parseFloat($(this).attr("data-fill"));
var fillAmount = perimeter - perimeter * amount / 100;
$(this).attr({
"stroke-dasharray":perimeter,
"stroke-dashoffset":fillAmount
})
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<svg width="300px" height="300px" viewbox="0 0 100 100">
<!-- Center color -->
<circle cx="50" cy="50" r="40" fill="#eee" id="radius"/>
<!-- Default color of ring -->
<circle cx="50" cy="50" r="40" fill="transparent" stroke-width="20" stroke="grey"/>
<!-- Progress -->
<!-- The amount shown as 'filled' is the amount the ring fills, starting from right center (3 o' clock) -->
<!-- 100% fill -->
<circle cx="50" cy="50" r="40" fill="transparent" stroke-width="20" stroke="#2196f3" data-fill="100" class="progress"/>
<!-- 80% fill -->
<circle cx="50" cy="50" r="40" fill="transparent" stroke-width="20" stroke="#ff5722" data-fill="80" class="progress"/>
<!-- 70% filled -->
<circle cx="50" cy="50" r="40" fill="transparent" stroke-width="20" stroke="#009688" data-fill="70" class="progress"/>
<!-- 50% filled -->
<circle cx="50" cy="50" r="40" fill="transparent" stroke-width="20" stroke="#9c27b0" data-fill="50" class="progress"/>
<!-- 40% filled -->
<circle cx="50" cy="50" r="40" fill="transparent" stroke-width="20" stroke="#e91e63" data-fill="40" class="progress"/>
<!-- 20% filled -->
<circle cx="50" cy="50" r="40" fill="transparent" stroke-width="20" stroke="#f44336" data-fill="20" class="progress"/>
<!-- Center Text -->
<text x="40" y="50" fill="black" font-size="10">Text</text>
</svg>

Related

Math to create SVG pie chart without using CSS or JS

I am seeking to create a pie chart in pure SVG. I do not want to use JS or CSS, which most of the solutions on this site utilize. I came across this great article that explains how to create a pie chart in pure SVG: https://seesparkbox.com/foundry/how_to_code_an_SVG_pie_chart
The problem is that this article only describes how to make only one slice. I am seeking to create a pie chart that can contain up to a maximum of 360 elements (in which each slice of the pie will be ‭0.27‬% of it).
I have attempted to create another wedge in the following example by rotating it to -89 instead of the -90, but I'm not getting the results I'm looking for: https://codepen.io/HexylCinnamal/pen/KKwEjpK
<svg xmlns="http://www.w3.org/2000/svg" height="100%" width="100%" viewBox="0 0 20 20">
<circle r="10" cx="10" cy="10" fill="transparent"/>
<circle r="5" cx="10" cy="10" fill="transparent" stroke="tomato" stroke-width="10"
stroke-dasharray="calc(1 * 31.4 / 100) 31.4" transform="rotate(-90) translate(-20)"/>
<circle r="5" cx="10" cy="10" fill="transparent" stroke="blue" stroke-width="10"
stroke-dasharray="calc(1 * 31.4 / 100) 31.4" transform="rotate(-89) translate(-20)"/>
</svg>
I was wondering if there is any math I need to do to calculate the proper angle and translation to make the blue wedge appear next to the red one.
Unfortunately, calc() to calculate the attribute stroke-dasharray only works inChrome
For a cross-browser solution, it is necessary to calculate and assign values in the stroke-dasharray.
stroke-dasharray ="Circumference * 0.35, Circumference" or stroke-dasharray = "31.4 * 0.35, 31.4" or stroke-dasharray="10.99 31.4"
<svg height="20%" width="20%" viewBox="0 0 20 20" style="border:1px solid gray; ">
<circle r="10" cx="10" cy="10" fill="white" />
<circle r="5" cx="10" cy="10" fill="bisque"
stroke="tomato"
stroke-width="10"
stroke-dasharray="10.99 31.4" />
</svg>
For two segments:
red="35%"
blue="15%" stroke-dasharray = 31.4 * 0.15, 31.4 or stroke-dasharray ="4.71, 31.4"
<svg height="20%" width="20%" viewBox="0 0 20 20" style="border:1px solid; ">
<circle r="10" cx="10" cy="10" fill="white" />
<circle r="5" cx="10" cy="10" fill="bisque"
stroke="tomato"
stroke-width="10"
stroke-dasharray="10.99 31.4" />
<circle r="5" cx="10" cy="10" fill="bisque"
stroke="dodgerblue"
stroke-width="10"
stroke-dasharray="4.71 31.4" />
</svg>
We see that the blue sector overlaps the red sector; therefore, it is necessary to shift the blue sector by an amount equal to the length of the red sector 10.99
Add to shift the blue sector stroke-dashoffset="-10.99"
<svg height="20%" width="20%" viewBox="0 0 20 20" style="border:1px solid; ">
<circle r="5" cx="10" cy="10" fill="bisque" />
<circle r="5" cx="10" cy="10" fill="transparent"
stroke="tomato"
stroke-width="10"
stroke-dasharray="10.99 31.4" />
<circle r="5" cx="10" cy="10" fill="transparent"
stroke="dodgerblue"
stroke-width="10"
stroke-dasharray="4.71 31.4"
stroke-dashoffset="-10.99"
/>
</svg>
Four sectors
The solution works in all modern browsers including MS Edge
<!-- https://seesparkbox.com/foundry/how_to_code_an_SVG_pie_chart -->
<svg height="20%" width="20%" viewBox="0 0 20 20" style="border:1px solid; ">
<circle r="5" cx="10" cy="10" fill="bisque" />
<circle r="5" cx="10" cy="10" fill="transparent"
stroke="tomato"
stroke-width="10"
stroke-dasharray="10.99 31.4" />
<circle r="5" cx="10" cy="10" fill="transparent"
stroke="dodgerblue"
stroke-width="10"
stroke-dasharray="4.71 31.4"
stroke-dashoffset="-10.99"
/>
<circle r="5" cx="10" cy="10" fill="transparent"
stroke="gold"
stroke-width="10"
stroke-dasharray="9.42 31.4"
stroke-dashoffset="-15.7"
/>
<circle r="5" cx="10" cy="10" fill="transparent"
stroke="yellowgreen"
stroke-width="10"
stroke-dasharray="6.28 31.4"
stroke-dashoffset="-25.12"
/>
<text x="10" y="15" font-size="3px" fill="black" >35%</text>
<text x="1" y="14" font-size="3px" fill="black" >15%</text>
<text x="4" y="6" font-size="3px" fill="black" >30%</text>
<text x="12" y="8" font-size="3px" fill="black" >20%</text>
</svg>
One easy way to fix your problem is using a different viewBox: "-10 -10 20 20"making the point 0,0 the center of the svg canvas. Please observe that you don't need the cx and cy attributes anymore and the transformation is only rotating.
I'm supposing that you want to divide the circle in 100 parts. In this case you'll need to rotate the second circle -90 + 360/100 or -90 - 360/100 degs.
circle{stroke-dasharray:calc(31.4 / 100) 31.4;}
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-10 -10 20 20">
<circle r="10" fill="transparent"/>
<circle r="5" fill="transparent" stroke="tomato" stroke-width="10" transform="rotate(-90)"/>
<circle r="5" fill="transparent" stroke="blue" stroke-width="10" transform="rotate(-86.4)"/>
</svg>

how to draw circles using html and css like this?

I've been trying to draw this circle here's my code so far.
<div class="circle">
<svg height="360" width="380">
<circle cx="50" cy="50" r="50" fill="rgb(177,236,250"></circle>
<circle cx="100" cy="120" r="90" fill="rgb(177,236,250)" ></circle>
<circle cx="290" cy="220" r="160" fill="rgb(177,236,250)"></circle>
<circle cx="80" cy="220" r="80" fill="rgb(177,236,250)"></circle>
</svg>
</div>
but it looks so different.
You need to use rgba instead of RGB to set transparency:
<div class="circle">
<svg height="360" width="380">
<circle cx="50" cy="50" r="50" fill="rgba(177,236,250,0.5)"></circle>
<circle cx="100" cy="120" r="90" fill="rgba(177,236,250,0.5)" ></circle>
<circle cx="290" cy="220" r="160" fill="rgba(177,236,250,0.5)"></circle>
<circle cx="80" cy="220" r="80" fill="rgba(177,236,250,0.5)"></circle>
</svg>
</div>
You can use rgba for transparent colors. Also, you can use "position:relative;z-index:(order)" to determine which one will appear at the top.
<div class="circle">
<svg height="360" width="380">
<circle cx="50" cy="50" r="50" fill="rgba(177,236,250,.8)" style="position:relative;z-index:1"></circle>
<circle cx="100" cy="120" r="90" fill="rgba(177,236,250,.5)" style="position:relative;z-index:4"></circle>
<circle cx="290" cy="220" r="160" fill="rgba(177,236,250,.4)" style="position:relative;z-index:3"></circle>
<circle cx="80" cy="220" r="80" fill="rgb(177,236,250,.7)" style="position:relative;z-index:2"></circle>
</svg>
</div>
<div class="circle">
<svg height="360" width="380">
<circle cx="50" cy="50" r="50" fill="rgb(177,236,250,0.5"></circle>
<circle cx="100" cy="120" r="90" fill="rgb(177,236,250,0.7)" ></circle>
<circle cx="290" cy="220" r="160" fill="rgb(177,236,250,0.5)"></circle>
<circle cx="80" cy="220" r="80" fill="rgb(177,236,250,0.5)"></circle>
</svg>
</div>
Sea this one.
You need to add transparency to your colors, replace fill="rgb(177,236,250)" with fill="rgba(177,236,250,0.5)". The 0.5 is the alpha value of your color, the value go from 0 (fully transparent) to 1 (opaque).
<div class="circle">
<svg height="360" width="380">
<circle cx="50" cy="50" r="50" fill="rgba(177,236,250,0.5)"></circle>
<circle cx="100" cy="120" r="90" fill="rgba(177,236,250,0.5)" ></circle>
<circle cx="290" cy="220" r="160" fill="rgba(177,236,250,0.5)"></circle>
<circle cx="80" cy="220" r="80" fill="rgba(177,236,250,0.5)"></circle>
</svg>
</div>

Transparent overlapping circles without border in background

Is it possible to implement transparent overlapping svg circle elements without circles border in transparent area?
You can clip the bits you don't want to draw...
<svg height="100" width="150">
<defs>
<clipPath id="clip" clipPathUnits="objectBoundingBox">
<rect width="0.79" height="1.2" x="-0.1" y="-0.1"/>
</clipPath>
</defs>
<rect width="100%" height="100%" fill="blue" opacity="0.2" />
<circle cx="80" cy="50" r="40" stroke="black" stroke-width="3" fill="none" />
<circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="none" clip-path="url(#clip)"/>
</svg>
Check this link to view information about position absolute css code. I think this is what you are looking for. You might also want to view information about z-index. If you have any questions or want me to write some sample code for your problem let me know
svg{
position: absolute;
}
#svg-1{
top: 80px;
left: 20px;
}
#svg-2{
top: 80px;
left: 60px;
}
<svg id="svg-1" height="100" width="100">
<circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="red" /></svg>
<svg id="svg-2" height="100" width="100">
<circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="red" /></svg>
You can also use a <mask>.
I've used the same elements as #RobertLongson's answer so you can compare the approaches.
<svg height="100" width="150">
<defs>
<mask id="mask">
<!-- white rectangle to keep the area outside the circle -->
<rect width="100%" height="100%" fill="white"/>
<!-- black circle creates a "hole" to hide the part inside -->
<circle cx="50" cy="50" r="40" fill="black"/>
</mask>
</defs>
<rect width="100%" height="100%" fill="blue" opacity="0.2" />
<circle cx="80" cy="50" r="40" stroke="black" stroke-width="3" fill="none"
mask="url(#mask)"/>
<circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="none"/>
</svg>

SVG viewBox scaling and cropping

How can I output a certain place from SVG and zoom it?
E. g., I have the following HTML with SVG (the copy of the code and its render are located at http://jsfiddle.net/5e0pas9m/ ).
<div style="border: 1px solid black;">1
<svg width="100" height="100" viewBox="0 0 200 200" style="border: 1px solid red; transform: scale(1);" preserveAspectRatio="xMidYMid none">
<rect width="100%" height="100%" style="fill:rgb(200,200,255);stroke-width:4;stroke:rgb(100,100,255)" />
<circle cx="50" cy="50" r="40" stroke="green" stroke-width="4" fill="yellow" />
<circle cx="150" cy="150" r="40" stroke="red" stroke-width="4" fill="yellow" />
</svg>
</div>
<div style="border: 1px solid black;">2
<svg width="100" height="100" viewBox="0 0 100 100" style="border: 1px solid red; transform: scale(1);" preserveAspectRatio="xMidYMid none">
<rect width="100%" height="100%" style="fill:rgb(200,200,255);stroke-width:4;stroke:rgb(100,100,255)" />
<circle cx="50" cy="50" r="40" stroke="green" stroke-width="4" fill="yellow" />
<circle cx="150" cy="150" r="40" stroke="red" stroke-width="4" fill="yellow" />
</svg>
</div>
<div style="border: 1px solid black;">3
<svg width="100" height="100" viewBox="100 100 200 200" style="border: 1px solid red; transform: scale(1);" preserveAspectRatio="xMidYMid none">
<rect width="100%" height="100%" style="fill:rgb(200,200,255);stroke-width:4;stroke:rgb(100,100,255)" />
<circle cx="50" cy="50" r="40" stroke="green" stroke-width="4" fill="yellow" />
<circle cx="150" cy="150" r="40" stroke="red" stroke-width="4" fill="yellow" />
</svg>
</div>
<div style="border: 1px solid black;">4
<svg width="100" height="100" style="border: 1px solid red; transform: scale(1);" preserveAspectRatio="xMidYMid none">
<g transform="scale(1), translate(-100 -100)">
<rect width="100%" height="100%" style="fill:rgb(200,200,255);stroke-width:4;stroke:rgb(100,100,255)" />
<circle cx="50" cy="50" r="40" stroke="green" stroke-width="4" fill="yellow" />
<circle cx="150" cy="150" r="40" stroke="red" stroke-width="4" fill="yellow" />
</g>
</svg>
</div>
The div-1 shows my full image.
If I like to show only the top-left corner in the same window I make viewBox="0 0 100 100" (div-2) and it gives approximately what I want: the part of the image fitted to the window.
But when I do the same thing with the right-bottom corner (div-3 represents viewBox="100 100 200 200") the image is only translated but is not fitted/zoomed/scaled.
The div-4 nealry shows an example of my target achieved via another technique.
The third and fourth arguments of the viewBox are width and height, not maxX and maxY. So the viewBox for your bottom-right example should be "100 100 100 100".

Display a lot of images in background (SVG)

I would like to display, in SVG, a lot of circles. Each of us would contain an image.
I've found a way for doing that. I define a pattern :
<defs>
<pattern preserveAspectRatio="true" patternContentUnits="objectBoundingBox" height="1" width="1" y="0" x="0" id="imageExample">
<image height="1" width="1" y="0" x="0" xlink:href="img/imageExample.png"/>
</pattern>
</defs>
And then I display the circle :
<circle cx=x cy=y r=r stroke="white" stroke-width="2" fill="url(#imageExample)"/>
My question is : is it necessary to define 1000 patterns if I want to display 1000 circles ?
[edit] I want that each circle has a different background image, sorry.
of course, i isn't. see the demo below, also avaliable online:
<?xml version="1.0" encoding="utf-8"?>
<!-- SO: http://stackoverflow.com/questions/16174765/display-a-lot-of-images-in-background-svg -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xhtml="http://www.w3.org/1999/xhtml"
xmlns:xlink="http://www.w3.org/1999/xlink"
version="1.1"
width="20cm" height="20cm"
viewBox="0 0 1000 1000"
preserveAspectRatio="xMinYMin"
style="background-color:white; border: solid 1px black;"
>
<defs>
<pattern preserveAspectRatio="true" patternContentUnits="objectBoundingBox" height="1" width="1" y="0" x="0" id="imageExample">
<image height="1" width="1" y="0" x="0" xlink:href="img/imageExample.png"/>
</pattern>
</defs>
<circle cx="123" cy="109" r="10" stroke="black" stroke-width="1" fill="url(#imageExample)"/>
<circle cx="456" cy="332" r="10" stroke="black" stroke-width="1" fill="url(#imageExample)"/>
<circle cx="12" cy="444" r="10" stroke="black" stroke-width="1" fill="url(#imageExample)"/>
<circle cx="77" cy="567" r="10" stroke="black" stroke-width="1" fill="url(#imageExample)"/>
<circle cx="66" cy="712" r="10" stroke="black" stroke-width="1" fill="url(#imageExample)"/>
<circle cx="47" cy="855" r="10" stroke="black" stroke-width="1" fill="url(#imageExample)"/>
<circle cx="843" cy="30" r="10" stroke="black" stroke-width="1" fill="url(#imageExample)"/>
<circle cx="112" cy="321" r="10" stroke="black" stroke-width="1" fill="url(#imageExample)"/>
<circle cx="387" cy="543" r="10" stroke="black" stroke-width="1" fill="url(#imageExample)"/>
<circle cx="444" cy="67" r="10" stroke="black" stroke-width="1" fill="url(#imageExample)"/>
</svg>