How to set up smartphones and PCs. Informational portal

Pie chart html. Pie and donut svg charts in HTML5 from scratch

  • Translation
  • Tutorial

Forms are a great way to add some flavor to elements on your web page. Circles are especially good in this regard because they are holistic, simple, and pie-like. Now seriously, who doesn't love pie?

As you must have noticed from your own years of experience using the Internet, most of the elements on web pages are, in fact, either squares or rectangles. Therefore, in some cases, interesting elements such as circles and triangles in your design can be quite useful. This tutorial will demonstrate how to build an animated pie chart, similar to those that you usually see on portfolio sites. This can help visually highlight your skills, as well as demonstrate what tasks you can handle. Take a look at the demo to see the final result.

So, let's begin!

When writing this tutorial, I will be working with Circliful. It is a free and open source jQuery plugin. You can download the main file from Github. It includes a .js file along with a corresponding CSS style sheet. The page must contain both in order to achieve the circle effect.




 
 
 Animated Circle Stats - Template Monster Demo
 
 
 
 
 
 
 

My page contains a similar styles.css stylesheet for my personal CSS styles. You also need to make a copy of the jQuery library. It is required for the plugin to work correctly.
By itself, the page is fairly easy to structure. Circle elements are contained within div tags that use HTML5 attributes to manipulate data. Alternatively, they can be stored in jQuery functions but if you want better control over each element then it's easier to work in HTML.

Photoshop

Illustrator

After Effects

This is a copy of the first row of circles, consisting of 3 animated units. All these data attributes are further explained in the plugin documentation. Each represents an option that defines an animation effect. I give below short description options I use:

  • data-dimension - total size of the circle width / height;
  • data-text - the text that appears in the center of each circle;
  • data-width - thickness of the rotating data arc;
  • data-fontsize - center text font size;
  • data-percent - a number from 0-100 representing the percentages in your circle;
  • data-fgcolor - the foreground color of the circle;
  • data-bgcolor - background color of the circle;
  • data-fill - the inner fill of the background color of the inner circle.

CSS page layout

I do not insist that you directly edit jquery.circliful.css unless you want to customize the plugin, of course. Most of the colors can be changed directly from HTML5 data attributes, and if you really want to rewrite any of the styles Circliful, I would recommend that you do this in your own stylesheet.
Having told you this, I created my own stylesheet for the given project, not to rewrite styles Circliful... The web page itself needs a default layout that is really easy to design. The content area is centered in a small section for a pie chart. Each area moves freely within the line container within the original #stats div.

/ ** page structure ** / .wrap (display: block; margin: 0 auto; max-width: 800px;) #intro (display: block; margin-bottom: 25px; text-align: center;) #intro p  (font-size: 1.8em; line-height: 1.35em; color: # 616161; font-style: italic; margin-bottom: 25px;) #stats (display: block; width: 100%; padding: 15px 0;  background: # f8f8f8; border-top: 4px solid # c3c3c3; border-bottom: 4px solid # c3c3c3;) #stats .row (display: block;) .circle-container (display: block; float: left; margin-right  : 55px; margin-bottom: 45px;) .circle-container h3 (display: block; text-align: center; font-size: 2.25em; line-height: 1.4em; color: # 363636; text-shadow: 1px  1px 0 #fff;)

Within each section, content is kept within .wrap div for fixing in the center. Also, freely moving elements of the circle need an additional container. .clearfix to keep everything correctly aligned.

/ ** clearfix ** / .clearfix: after (content: "."; display: block; clear: both; visibility: hidden; line-height: 0; height: 0;) .clearfix (display: inline-block;  ) html .clearfix (display: block;) * html .clearfix (height: 1%;)

This class clearfix has been known for years as a free-moving container solution. Usually they are removed from the text of the document and do not preserve their original width / height. But this keeps the container width constant #stats and leaves room for more content that will be located below on the page.

Final touches

So, we kneaded the dough, filled the pie pan, put it in the oven and are almost ready to sample it. If everything looks good enough, what is the final step? We need some jQuery code to decorate this project.
Open a new script tag at the bottom of this HTML pages... It will contain a small snippet of JavaScript. Since I've used all HTML5 data attributes, we don't need to call any jQuery options. The script just has to run the function Circliful on each circle of divs. Using a duplicated class name such as .circlestat makes the process very easy.

$ (function () ($ (". circlestat"). circliful ();));

For those unfamiliar with the jQuery syntax structure, I'll provide a short description. After the document is loaded, we run new function... Our inner goal is every element that uses the class .circlestat and runs the function circliful ()... This leads the plugin Circliful, which creates animation effects, into action and applies additional content / colors.

I can't say these circles will always be the best solution... I've seen a lot of portfolios that were based on words and numbers, but not work per se. Consider using these circles on rare occasions and try borrowing them for purposes other than simple skills. Your statistics do not have to be measured as a percentage - they can show how many years you have been in business, the total number of projects you have, or other similar numbers. You can download a copy of my tutorial for free and experiment with the code to make it better for your projects.

Though pie charts are the most common way of presenting information, ranging from simple statistics to progress indicators and timers, even in their simplest two-color form, they have traditionally been created in any way other than simple methods using web technologies. Usually, for their implementation, either external graphic editor for creating multiple images for multiple pie chart values or JavaScript frameworks for creating more complex diagrams.

Although now the task does not seem as impossible as it was before, there is still no simple unambiguous solution. However, there are many better ones today (compared to the methods above), more supported ways to implement pie charts.

A transform-based solution

This solution is the best in terms of markup: it only needs one element, and everything else will be done using pseudo-elements, transformations and CSS gradients... Let's start with a simple element:

Now, let's suppose we want a pie chart that displays hard-coded 20% ... We'll work on making it flexible later. First, we'll style the element as a circle, which will be our background (Figure 1):

Figure 1 - Our starting point (pie chart displaying 0%) .pie (width: 100px; height: 100px; border-radius: 50%; background: yellowgreen;)

Our pie chart will be green (more specifically yellowgreen) with a brown sector (# 655) showing the percentage. We might be tempted to use oblique transformations for the percentage, but as a little experimentation shows, this would be a rather sloppy solution. Instead, we'll color the left and right sides of our circle with two colors and use rotation of the pseudo-element to reveal only the fraction of the circle that we need.

To color the right side of our circle brown, we'll use a simple linear gradient:

Background-image: linear-gradient (to right, transparent 50%, # 655 0); Figure 2 - Coloring the right side of our circle brown with a simple linear gradient

As you can see in Figure 2, that's all we needed. Now we can start styling the pseudo-element that will act as a mask:

Pie :: before (content: ""; display: block; margin-left: 50%; height: 100%;) Figure 3 - The pseudo-element acting as a mask is highlighted here with a dashed border

In Figure 3, you can see how in this moment our pseudo-element is located relative to the pie chart element. Now it is not yet stylized and does not perform any functions. It's just an invisible rectangle. Before we start styling it, let's make a few comments:

  • as we want hide the brown part of our circle, then we have to apply to the pseudo-element green background using background-color: inherit to avoid duplication when assigning it the same background color as parent element;
  • we want him revolved around the center of the circle which is in the middle of the left side of the pseudo-element, so we have to set the transform-origin to 0 50% or just left;
  • we don’t want it to be a rectangle as it will overflow the edges of the pie, so we have to either apply overflow: hidden to the .pie or give it a border-radius to make it a semicircle.

Putting it all together, we get the following styling for our pseudo-element;

Pie :: before (content: ""; display: block; margin-left: 50%; height: 100%; border-radius: 0 100% 100% 0/50%; background-color: inherit; transform-origin: left;) Figure 4 - Our pseudo-element (shown with a dashed border) after finishing styling

Note: Do not use background: inherit; instead of backround-color: inherit;, as this will inherit the gradient!

Our pie chart now looks like Figure 4. This is where the fun begins! We can begin rotate pseudo element by applying the rotate () transformation. For 20% we are trying to implement, we can use 72deg (0.2 × 360 = 72), or 2turn which is more readable. In Figure 5, you can see how this looks for several other values ​​as well.

Figure 5 - Our simple pie chart showing different percentages, from left to right: 10% (36deg or 1turn), 20% (72deg or 2turn), 40% (144deg or 4turn)

You might think that the job is done, but, unfortunately, not everything is so simple. Our pie chart is great for displaying percentages from 0 to 50%, but if we try to display a 60 percent rotation (using 6turn), we get what is shown in Figure 6. But don't give up hope, we can fix this. and let's do it!

Figure 6 - Our pie chart breaks down for shares more than 50%(shown here for 60%)

If we consider the display of 50% -100% shares as a separate problem, then you can see that for them we can use an inverted version of the previous solution: brown pseudo-element rotating from 0 to 5turn respectively. So, for a 60% share, the pseudo-element code will look like this:

Pie :: before (content: ""; display: block; margin-left: 50%; height: 100%; border-radius: 0 100% 100% 0/50%; background: # 655; transform-origin: left ; transform: rotate (.1turn);) Figure 7 - Our now correct pie chart with a value of 60%

In Figure 7, you can see the code in action. Since now we have developed a way to display any percentage, we can and animate a pie chart from 0% to 100% with using CSS animations by creating a kind of progress indicator:

@keyframes spin (to (transform: rotate (.5turn);)) @keyframes bg (50% (background: # 655;)) .pie :: before (content: ""; display: block; margin-left: 50 %; height: 100%; border-radius: 0 100% 100% 0/50%; background-color: inherit; transform-origin: left; animation: spin 3s linear infinite, bg 6s step-end infinite;)

It's okay, but how do we style multiple static pie charts with different percentages, which is the most general case using charts? Ideally, we want to be able to print something like this:

20%
60%

And get two pie charts, one showing 20% ​​and the other showing 60%. First, we'll look at how we can do this using inline styles, and then we can always write a short script to parse text content and add the specified inline styles for code elegance, encapsulation, maintainability, and perhaps most importantly, accessibility.

The tricky part about controlling the percentage of a pie chart with inline styles is that the CSS that is responsible for setting the percentage is set to a pseudo element. As you already know, we cannot set inline styles on pseudo-elements, That's why we will have to be more inventive.

Note: For use values ​​from the color spectrum no repetitions and complex calculations you can use the method below. You can use this method in other cases as well. Below is a simple, isolated example of using this technique.

The solution comes from one of the most unexpected places. We are going to use the animation that has already been shown, but which will be paused. Instead of running it like a normal animation, we'll use negative animation delays to set a position at any point in the animation and stay there. Are you surprised? Yes, negative animation-delay values ​​are not only allowed in the spec, but are very useful in such cases.

Since our animation is paused, only its first frame will be shown (determined by our negative value animation-delay). The percentage shown in the pie chart will be equal to the percentage our animation-delay makes in the total duration. For example, with a current duration of 6s, we need an animation-delay of -1.2s to show a 20% fraction. To simplify the calculations, we will set the duration to 100s. Keep in mind that since the animation is permanently stopped, the value we set for its duration does not play any other role.

And the last question: the animation is applied to the pseudo-element, but we want to set the inline style to the .pie element... However, although on

no animation, we can set animation-delay to it as inline style and then use animation-delay: inherit; for a pseudo element. Putting it all together, our markup for the 20% and 60% pie charts looks like this:

And the CSS code for this animation becomes the following (the rules for .pie are not shown, as they remain the same):

@keyframes spin (to (transform: rotate (.5turn);)) @keyframes bg (50% (background: # 655;)) .pie :: before (/ * [other styles have not changed] * / animation: spin 50s linear infinite, bg 100s step-end infinite; animation-play-state: paused; animation-delay: inherit;)

For now, we can convert the markup to use percentages as content, as we originally intended, and add inline animation-delay styles through a simple script:

$$ (". pie"). forEach (function (pie) (var p = parseFloat (pie.textContent); pie.style.animationDelay = "-" + p + "s";));

Please note that we have left the text intact as we need it for accessibility and usability. Our pie charts now look like Figure 8. We need to hide the text that can be made available via color: transparent so that it stays selectable and printable... For extra gloss, we can place percentage values ​​in the center of the pie chart so that they are not in random place when the user tries to highlight them. To do this, we need:

Figure 8 - Our text before we hide it

  • convert the height value of the chart to line-height (or add a line-height value equal to height, but this would be pointless duplication of code, since the line-height will be set to the calculated height value, which is good);
  • set the size and position of the pseudo element with absolute positioning so that he does not push the text down;
  • add text-align: center; to center the text horizontally.

The final code looks like this:

Pie (position: relative; width: 100px; line-height: 100px; border-radius: 50%; background: yellowgreen; background-image: linear-gradient (to right, transparent 50%, # 655 0); color: transparent ; text-align: center;) @keyframes spin (to (transform: rotate (.5turn);)) @keyframes bg (50% (background: # 655;)) .pie :: before (content: ""; position : absolute; top: 0; left: 50%; width: 50%; height: 100%; border-radius: 0 100% 100% 0/50%; background-color: inherit; transform-origin: left; animation: spin 50s linear infinite, bg 100s step-end infinite; animation-play-state: paused; animation-delay: inherit;)

SVG based solution

SVG makes the decision of many graphics tasks simpler and pie charts are no exception. However, instead of creating a pie chart using paths, which would require complicated math, we'll use a little trick.

Let's start with a circle:

Now let's apply some basic styles to it:

Circle (fill: yellowgreen; stroke: # 655; stroke-width: 30;)

Note: As you know, these CSS properties are also available as attributes SVG elements that might come in handy if porting was a concern.

Figure 9 - Our starting point: a green SVG circle with a thick # 655 stroke

You can see our outlined circle in Figure 9. Strokes in SVG are made up of more than just the stroke and stroke-width properties. There are many other less popular stroke-related properties that allow you to fine-tune their appearance. One of them is stroke-dasharray, which is for creating dashed strokes. For example, we could use it to do this:

Stroke-dasharray: 20 10; Figure 10 - Simple dashed stroke created with stroke-dasharray

This means that we want a dash of length 20 with gaps of length 10, like the ones shown in Figure 10. At this point, you might be surprised that this SVG example has something to do with pie charts. But things become clearer when we apply a stroke with a dash of 0 and gaps longer than or equal length the circumference of our circle (C = 2πr, or in our case C = 2π × 30 ≈ 189):

Stroke-dasharray: 0 189; Figure 11 - Several stroke-dasharray values ​​and their result; from left to right: 0 189; 40 189; 95 189; 150 189

As you can see, in the first circle in Figure 11, this removes the stroke completely, and we're left with only the green circle. However, the fun begins when we start increasing the first value (Figure 11): due to such a long gap, we will no longer get dotted stroke, but a stroke that covers as much of the circle's circumference as we specify.

You may have already figured out which way we are moving: if we reduce the radius of our circle enough so that it completely obscures its stroke, we will end up with something very much like a pie chart. For example, in Figure 12, you can see how this would look when applied to a circle with a radius of 25 and a stroke-width of 50:

Figure 12 - Our SVG image begins to resemble a pie chart

Remember: SVG strokes are always half inside and half outside the element they are applied to. In the future, we will be able to control this behavior.

circle (fill: yellowgreen; stroke: # 655; stroke-width: 50; stroke-dasharray: 60 158; / * 2π × 25 ≈ 158 * /)

Now turning this image into a pie chart like the one we created in the previous solution is pretty easy: you just need to add a larger green circle for the stroke and rotate it 90 ° counterclockwise so that it starts at the top in the middle. Insofar as element is also HTML element, we can just style it:

Svg (transform: rotate (-90deg); background: yellowgreen; border-radius: 50%;) Figure 13 - Final Pie Chart with SVG

You can see the final result in Figure 13. This method makes it even easier to animate the pie chart from 0% to 100%. We just need to create a CSS animation that changes the stroke-dasharray from 0 158 to 158 158:

@keyframes fillup (to (stroke-dasharray: 158 158;)) circle (fill: yellowgreen; stroke: # 655; stroke-width: 50; stroke-dasharray: 0 158; animation: fillup 5s linear infinite;)

As an additional refinement, we can set a certain radius of the circle so that its circumference is (infinitely close to) 100, so we can specify stroke-dasharray lengths as percentages, without any calculations. Since the circumference is 2πr, we need a radius of 100 ÷ 2π ≈ 15.915494309, which for our needs can be rounded to 16. We also set the dimensions of the SVG in the viewBox attribute, instead of width attributes and height to make it resizable to the size of its container.

With these modifications, the markup for the pie chart shown in Figure 13 becomes:

And the CSS will be like this:

Svg (width: 100px; height: 100px; transform: rotate (-90deg); background: yellowgreen; border-radius: 50%;) circle (fill: yellowgreen; stroke: # 655; stroke-width: 32; stroke-dasharray : 38 100; / * for 38% * /)

Note, how easy it is now to change the percentage... Even with this oversimplification, though, we don't want to repeat all this SVG markup for every pie chart. It's time for JavaScript to help us with a little automation. We'll write a small script to take simple HTML markup like this ...

20%
60%

And add inline SVG inside each .pie element with all essential elements and attributes. It will also add the element for accessibility so that users <a href="https://bumotors.ru/en/skachat-golosovoi-dvizhok-dlya-android-ekrannyi-diktor-dlya.html">screen readers</a> could also find out what percentages are displayed. The final script will look like this:</p><p>$$ (". pie"). forEach (function (pie) (var p = parseFloat (pie.textContent); var NS = "http://www.w3.org/2000/svg"; var svg = document. createElementNS (NS, "svg"); var circle = document.createElementNS (NS, "circle"); var title = document.createElementNS (NS, "title"); circle.setAttribute ("r", 16); circle. setAttribute ("cx", 16); circle.setAttribute ("cy", 16); circle.setAttribute ("stroke-dasharray", p + "100"); svg.setAttribute ("viewBox", "0 0 32 32 "); title.textContent = pie.textContent; pie.textContent =" "; svg.appendChild (title); svg.appendChild (circle); pie.appendChild (svg);));</p><p>Here it is! You might think that <a href="https://bumotors.ru/en/podklyuchenie-stilei-css-kak-podklyuchit-css-metody-i-sposoby-podklyuchenii.html">CSS method</a> better since its code is simpler and more familiar. However, the SVG method has certain advantages over the pure CSS solution:</p><ul><li><b>it's easier to add a third color</b>: just add another outlined circle and move its stroke with stroke-dashoffset. Or add its stroke length to the stroke length of the previous circle in front of (below) it. How exactly would you add the third color to the pie chart created in the first way?</li><li>we <b>should not put any extra effort into printing</b> since SVG elements are treated like content and printed in the same way as elements <img>... The first solution depends on the background and thus will not be printed;</li><li>we can <b>change colors using inline styles</b> which means that we can easily change them via <b>scripts</b>(i.e. depending on <b>user input</b>). The first solution relies on pseudo-elements, which cannot accept inline styles except through inheritance, which is not always convenient.</li> background: conic-gradient (# 655 attr (data-value%), yellowgreen 0); <p>It also makes incredible <a href="https://bumotors.ru/en/how-to-add-a-photo-in-contact-a-few-simple-waysssss.html">simple addition</a> third color. For example, for a pie chart, <a href="https://bumotors.ru/en/modelirovanie-informacionnyh-sistem-podobnymi-diagrammami-mozhno.html">similar diagram</a> above, we would just add two more color stops:</p><p>Background: conic-gradient (deeppink 20%, # fb3 0, # fb3 30%, yellowgreen 0);</p><p>That's all! Leave your comments!</p></ul> <p>You've probably come across these loading indicators, especially on Flash sites. This is a sector of a circle that gets larger and larger until it turns into a complete circle.</p> <p>At first glance, the task seems simple: make a circle, rotate it and hide the part behind a mask. But in reality, everything turns out to be somewhat more complicated. CSS is not prepared for such tasks, even when using preprocessors like SASS & Compass. We always struggle when we have to make different shapes, and especially when defining styles and animations for them. Most of the working time is spent on that. to get something working, and sacrifice the semantics of the code and its support.</p> <h2>Why do we do it?</h2> <p>The most likely use of such items is timers. But <a href="https://bumotors.ru/en/koncepciya-hranilishcha-dannyh-fizicheskie-i-virtualnye.html">this concept</a> can be used to make a pie chart in one CSS.</p> <p>While there are some amazing tools for manipulating pie charts (mostly in JavaScript), we will nevertheless make such an element in CSS only and even animate it with a few tricks.</p> <p>The semantics of the code will be so-so! But the accompaniment can be made quite convenient.</p> <h2>Html</h2> <p>We need 3 different elements:</p> <ul><li><b>spinner:</b> half of the circle that will rotate;</li> <li><b>mask:</b> this element hides the spinning circle during the first 50% of the animation;</li> <li><b>filler:</b> this element fills the circle during the last 50% of the animation.</li> </ul><p>And all three elements must have the same parent for absolute positioning:</p> <p> <div class="wrapper"> <div class="spinner pie"></div> <div class="filler pie"></div> <div class="mask"></div> </div></p> <p>Since spinner and filler are two halves of the same circle, we will use the .pie class for them.</p> <h2>CSS</h2> <p>The parent is sized and <a href="https://bumotors.ru/en/css-raspolozhenie-elementov-css---pozicionirovanie-blokov.html">absolute positioning</a> context for the timer:</p> <p>Wrapper (width: 250px; height: 250px; position: relative; background: white;)</p> <p>It is important that the width and height are equal in order to get the circle and everything works.</p> <p>The spinner and filler elements use <a href="https://bumotors.ru/en/velcom-kody-nomerov-baza-dannyh-mts.html">given code</a> CSS:</p> <p>Pie (width: 50%; height: 100%; position: absolute; background: # 08C; border: 10px solid rgba (0,0,0,0.4);)</p> <p>They have a width equal to 50% of the parent element, so they are two parts of the same circle, and their height is equal to the height of the parent element. We also define the same color and frame for them.</p> <h3>Spinner element</h3> <p>Spinner (border-radius: 125px 0 0 125px; z-index: 200; border-right: none; animation: rota 10s linear infinite;)</p> <p>Make it a semicircle using the border-radius property on the top-left and bottom-left corners. We also define a positive z-index to position it on top of the fill element, but below the mask.</p> <p>Then add animation for 10 seconds. We'll talk about animation later.</p> <h3>Filler element</h3> <p>Filler (border-radius: 0 125px 125px 0; z-index: 100; border-left: none; animation: fill 10s steps (1, end) infinite; left: 50%; opacity: 0;)</p> <p>For this element, set the border-radius and z-index, remove the border-left, and animate it for 10 seconds. For a given element, the animation-timing-function does not get a linear value, but steps (1, end). This means the animation will run instantly.</p> <p>Since the fill element should not be visible during the first half of the animation, its opacity will be 0 and its position will be 50% of the parent element's width.</p> <h3>The "mask" element</h3> <p>Mask (width: 50%; height: 100%; position: absolute; z-index: 300; opacity: 1; background: inherit; animation: mask 10s steps (1, end) infinite;)</p> <p>The mask is present from the beginning of the animation, so its opacity is set to 1 and the background is inherited from the parent (so that it is invisible). To cover the rotating element, it will have the same dimensions and the z-index property is set to 300.</p> <h3>Animation frames</h3> <p>@keyframes rota (0% (transform: rotate (0deg);) 100% (transform: rotate (360deg);)) @keyframes fill (0% (opacity: 0;) 50%, 100% (opacity: 1;) ) @keyframes mask (0% (opacity: 1;) 50%, 100% (opacity: 0;))</p> <p>The first animation (rota) is used for the spinner element. It rotates gradually from 0 to 360 degrees in 10 seconds.</p> <p>The second animation (fill) is used for the filler element. It immediately changes the opacity from 0 to 1 after 5 seconds.</p> <p>The last animation (mask) is used for the mask element. It immediately changes the opacity from 1 to 0 after 5 seconds.</p> <p>The animation looks like this:</p> <ul><li><b>T0</b>- the spinner is on the left, hidden by the mask. The filler element is hidden.</li> <li><b>T1</b>- the spinner starts spinning clockwise and slowly appears from behind the mask.</li> <li><b>T2</b>- the spinner r is rotated 360/10 * 2 = 72 ° and continues to rotate.</li> <li><b>T3</b>- the spinner is rotated 360/10 * 3 = 108 ° and continues to rotate.</li> <li><b>T4</b>- the spinner is rotated 360/10 * 4 = 144 ° and continues to rotate.</li> <li><b>T5</b>- the spinner is rotated 360/10 * 5 = 180 ° and continues to rotate. At this point, the filler element is instantly visible and the mask is hidden.</li> <li><b>T6</b>- the spinner is rotated 360/10 * 6 = 216 ° and continues to rotate.</li> <li><b>T7</b>- the spinner is rotated 360/10 * 7 = 252 ° and continues to rotate.</li> <li><b>T8</b>-the spinner is rotated 360/10 * 8 = 288 ° and continues to rotate.</li> <li><b>T9</b>- the spinner is rotated 360/10 * 9 = 324 ° and continues to rotate.</li> <li><b>T10</b>- the spinner is rotated 360 °. We returned to the starting point. Resetting the animation. The mask appears and the fill element is hidden.</li> </ul><h2>Bonus</h2> <p>A few additional tricks.</p> <h3>Pause on hover</h3> <p>Wrapper: hover .filler, .wrapper: hover .spinner, .wrapper: hover .mask (animation-play-state: paused;)</p> <p>With this code, you can stop all animation when you hover over the parent element.</p> <h3>Insert content</h3> <p>Thanks to the z-index property, we can easily add some content to the spinner and make it spin. Try the following code:</p> <p>Spinner: after (content: ""; position: absolute; width: 10px; height: 10px; border-radius: 50%; top: 10px; right: 10px; background: #fff; border: 1px solid rgba (0,0 , 0,0.4); box-shadow: inset 0 0 3px rgba (0,0,0,0.2);)</p> <h2>Preprocessor or CSS Variables</h2> <p>Currently, the code is very difficult to maintain. But if we use variables (in the preprocessor or expected internal <a href="https://bumotors.ru/en/peremennye-v-html-kode-nativnye-peremennye-v-css-uzhe-pora.html">css variables</a>), everything can become much easier. For example, you can add variables to control the duration instead of fixing the code in the 3 animation definitions.</p> <p>If you want to improve maintainability of your code without using preprocessors, you can create a class with one animation duration control and add it to 3 children. For example like this:</p> <p>Animation-duration (animation-duration: 10s;)</p> <p> <div class="wrapper"> <div class="spinner pie animation-duration"></div> <div class="filler pie animation-duration"></div> <div class="mask animation-duration"></div> </div></p> <h2>Flaws</h2> <p>This technique has several disadvantages:</p> <ul><li>Gradients are not supported.</li> <li>Shadows are not supported.</li> <li>No adaptability. If the parent element is resized, then everything will be fine, except for the radius of the rounding of the border. It will have to be changed manually.</li> <li>No semantics (4 elements for one animation).</li> </ul><h2>Browser support</h2> <p>Since we are using <a href="https://bumotors.ru/en/zaderzhka-animacii-css3-primery---obratnaya-animaciya-css-kratkaya.html">CSS animations</a>, then browser support is rather meager:</p> <ul><li>Internet Explorer 10</li> <li>Firefox 12+</li> <li>Chrome</li> <li>Safari 5+</li> <li>Opera 12+</li> <li>iOS Safari 3+</li> <li>Android 2+</li> </ul> <ul><li>Translation</li><li>Tutorial</li> </ul><p>Forms are a great way to add some flavor to elements on your web page. Circles are especially good in this regard because they are holistic, simple, and pie-like. Now seriously, who doesn't love pie?</p><p>As you must have noticed from your own years of experience using the Internet, most of the elements on web pages are, in fact, either squares or rectangles. Therefore, in some cases, interesting elements such as circles and triangles in your design can be quite useful. This tutorial will demonstrate how to build an animated pie chart similar to the ones you usually see on portfolio sites. This can help visually highlight your skills, as well as demonstrate what tasks you can handle. Take a look at the demo to see the final result.</p><h3>So, let's begin!</h3>When writing this tutorial, I will be working with Circliful. It is a free and open source jQuery plugin. You can download the main file from Github. It includes a .js file along with a corresponding CSS style sheet. The page must contain both in order to achieve the circle effect. <p> <pre lang="PHP" line="1"><!doctype html> <html lang="en-US"> <head> <meta charset="utf-8"> <meta http-equiv="Content-Type" content="text/html"> <title>Animated Circle Stats - Template Monster Demo

My page contains a similar styles.css stylesheet for my personal CSS styles. You also need to make a copy of the jQuery library. It is required for the plugin to work correctly.
By itself, the page is fairly easy to structure. Circle elements are contained within div tags that use HTML5 attributes to manipulate data. Alternatively, they can be stored in a jQuery function, but if you want better control over each element then it's easier to work in HTML.

Photoshop

Illustrator

After Effects

This is a copy of the first row of circles, consisting of 3 animated units. All these data attributes are further explained in the plugin documentation. Each represents an option that defines an animation effect. Below is a brief description of the options that I use:

  • data-dimension - total size of the circle width / height;
  • data-text - the text that appears in the center of each circle;
  • data-width - thickness of the rotating data arc;
  • data-fontsize - center text font size;
  • data-percent - a number from 0-100 representing the percentages in your circle;
  • data-fgcolor - the foreground color of the circle;
  • data-bgcolor - background color of the circle;
  • data-fill - the inner fill of the background color of the inner circle.

CSS page layout

I do not insist that you directly edit jquery.circliful.css unless you want to customize the plugin, of course. Most of the colors can be changed directly from HTML5 data attributes, and if you really want to rewrite any of the styles Circliful, I would recommend that you do this in your own stylesheet.
Having told you this, I created my own stylesheet for the given project, not to rewrite styles Circliful... The web page itself needs a default layout that is really easy to design. The content area is centered in a small section for a pie chart. Each area moves freely within the line container within the original #stats div.

/ ** page structure ** / .wrap (display: block; margin: 0 auto; max-width: 800px;) #intro (display: block; margin-bottom: 25px; text-align: center;) #intro p  (font-size: 1.8em; line-height: 1.35em; color: # 616161; font-style: italic; margin-bottom: 25px;) #stats (display: block; width: 100%; padding: 15px 0;  background: # f8f8f8; border-top: 4px solid # c3c3c3; border-bottom: 4px solid # c3c3c3;) #stats .row (display: block;) .circle-container (display: block; float: left; margin-right  : 55px; margin-bottom: 45px;) .circle-container h3 (display: block; text-align: center; font-size: 2.25em; line-height: 1.4em; color: # 363636; text-shadow: 1px  1px 0 #fff;)

Within each section, content is kept within .wrap div for fixing in the center. Also, freely moving elements of the circle need an additional container. .clearfix to keep everything correctly aligned.

/ ** clearfix ** / .clearfix: after (content: "."; display: block; clear: both; visibility: hidden; line-height: 0; height: 0;) .clearfix (display: inline-block;  ) html .clearfix (display: block;) * html .clearfix (height: 1%;)

This class clearfix has been known for years as a free-moving container solution. Usually they are removed from the text of the document and do not preserve their original width / height. But this keeps the container width constant #stats and leaves room for more content to go down the page.

Final touches

So, we kneaded the dough, filled the pie pan, put it in the oven and are almost ready to sample it. If everything looks good enough, what is the final step? We need some jQuery code to decorate this project.
Open a new script tag at the bottom of this HTML page. It will contain a small snippet of JavaScript. Since I've used all HTML5 data attributes, we don't need to call any jQuery options. The script just has to run the function Circliful on each circle of divs. Using a duplicated class name such as .circlestat makes the process very easy.

$ (function () ($ (". circlestat"). circliful ();));

For those unfamiliar with the jQuery syntax structure, I'll provide a short description. After the document is loaded, we run a new function. Our inner goal is every element that uses the class .circlestat and runs the function circliful ()... This leads the plugin Circliful, which creates animation effects, into action and applies additional content / colors.

I cannot say that these circles will always be the best solution. I've seen a lot of portfolios that were based on words and numbers, but not work per se. Consider using these circles on rare occasions and try borrowing them for purposes other than simple skills. Your statistics do not have to be measured as a percentage - they can show how many years you have been in business, the total number of projects you have, or other similar numbers. You can download a copy of my tutorial for free and experiment with the code to make it better for your projects.

A web developer's "kitchen" is a bit like home cooking. The developer has access to a variety of libraries from finished code that will help him make a web application in much the same way that a chef at home can use convenience foods to cook his dish more efficiently. In both cases, the quality of the pre-prepared items should be very important. However, sometimes quality is sacrificed for convenience. Don't get me wrong, convenience isn't always a bad thing. It can be useful when the pros and cons are known and well analyzed. Analyzing the options for pie and donut charts in HTML, we can only highlight a few:

  1. Canvas element-based chart generated on the client (i.e. JavaScript)
  2. A diagram based on SVG and generated on the client (i.e. JavaScript)
  3. SVG Based Chart Server Generated

Out-of-the-box libraries using Canvas and SVG JavaScript

JavaScript libraries for drawing diagrams are often more convenient and loaded with a bunch of cool options like interactivity. Here are some libraries:

  1. D3.js
  2. Chartist.js
  3. Google charts

A few lines of JavaScript and an array of data will allow you to create a diagram on your website in seconds. Not surprisingly, many choose this path.

So why bother and code them yourself? This is a great question that I also asked myself. In the end, I became convinced of three things:

  1. Most JavaScript libraries are hard to come by, especially those based on the Canvas element (with the exception of Google Charts)
  2. If the information in the diagram is very important (as it was in my situation), should we rely on a script running on the client to generate the information? I do not think so.
  3. If I dig deeper into the SVG code and get my hands dirty, I might learn a little more about the underlying magical nonsense. In other words, the learning process can be fun and worth the effort.

My situation

My team needed a simple component that could be built on the server and displayed simple information about using accounts. Also, our preference was for the lightness of this component (avoid JavaScript if possible); it didn’t have to be overly sophisticated or interactive, it only needed to display important data.

Additional note on Canvas based charts

You may have noticed (if you are familiar with creating charts for the web) that I have not included Chart.js in the list of recommended libraries above. While you can definitely use it, it's worth keeping in mind that Chart.js uses a Canvas element to render its charts, and the element's content is not part of the DOM. Therefore, they are not available to screen readers. This means that you have to accept additional measures to make sure your data is available.

An introduction to CSS and SVG charts

CSS and SVG diagrams are inherently more accessible and semantic than other technologies. But they can be complex, and possibly more time-consuming if you code them by hand.

CSS Ninja Lea Verou offers several options for creating pie charts from scratch in her article "Designing Flexible, Maintainable Pie Charts With CSS and SVG". Her methods can be applied to donut charts as well.

Robin Randle also wrote about creating charts purely with CSS, where he also points out his failures in the approach.

Inexplicable

I did some googling about SVG and donut charts and came across articles by Lea Verou and Robin Randle (mentioned above) in addition to several others. Almost all of them discussed the use of the stroke-dasharray and stroke-dashoffset attributes in SVG to position portions of a diagram. These properties are identical to "stroke" when creating vectors in programs such as Adobe Illustrator.

Some of these articles even discussed animation in SVG, which is cool, but it's also not what I was looking for.

After my research, I was able to figure out that using from SVG along with stroke and stroke-dasharray could provide me with the nested pie segments I needed. I also realized that stroke-dashoffset would allow me to "animate", or in other words, position the segment where I wanted it to be in the circle.

However, I didn't seem to find any clear explanation of exactly how the stroke dash attributes worked and how they related to the circumference of the circle. And what was more unattainable was attaching several elements (one after the other) around the circle. Better yet, what is the formula for getting these relative positions using the unique / dynamic segment sizes and stroke attributes of SVG?

So, I became determined to find out for myself.

Note: If you find any resources explaining these concepts, please share.

How to make a DIY SVG diagram

Explanation of stroke-dasharray and stroke-dashoffset

Let's start with a simple SVG "donut" chart.

You will notice a couple of things:

  1. The radius (attribute "r") looks absurd! Why? I wanted to make my segment sizes logical, understandable and readable. In order to achieve this, I decided to base everything on 100% (or a circle of 100). SVG shapes are scalable, so it doesn't really matter how big they end up; at least the math will be simple here. Moving further into the area that I remember from high school math: I know that the radius of a circle is r = C / (2π) or r = 100 / (2π). The result is 15.91549430918952. A crazy number with a bunch of numbers, yes, I know, but later it will make life easier for all of us.
  2. For viewBox the values ​​are "0 0 42 42". They must be double the cx & cy (center x and center y) values and be slightly larger than the diameter of the circles (including the width of the outline).
  3. There is with the "donut-hole" class. This is what is guaranteed to make the center white. If this is not important to you (in the case of a simple pie chart), then this item can be removed.
  4. Also there is with the "donut-ring" class. It serves as a light gray background in case the sectors do not fill 100% of the circle.

So, we need to adjust the sector size to the desired percentage. Let's use 85%:


The sectors are created using an SVG stroke attribute called stroke-dasharray. The value we set in the example above is "85 15".

If we think of the diagram as a circular one, then from the presence of an 85% sector, we can judge about the remainder of 15%. The two values ​​are a space delimited array. This is what happens: a bar of 85 is created, then a space of 15, then a bar of 85, a space of 15, and so on and so forth. But since we are using a circle and the total is 100, everything is repeated again. If we have not made the second value in the array such that it complements the first number to one hundred, then we will get the third stroke (or part) or more. For example, here's a stroke-dasharray from "10 10":


So, in shape 2 and shape 3, you can notice that the stroke-dasharray does not start at the very top (at 12:00). Instead, it actually starts with right side(3:00), and moves clockwise in a circle.

If we want to position (or start) on top, then we have to use stroke-dashoffset. However, unlike stroke-dasharray, stroke-dashoffset moves counterclockwise. So, we will need to set the value to "25" (25% in the other direction from 3:00, back to 12:00). Remember that this is not a negative number because offset is moving against the arrow.


How to arrange donut slices around SVG

Now we need to add additional sectors around the circle. Let's use a sector that is 15% of the circle. The remaining percentage for stroke-dasharray will be 85%, regardless of any other sectors. Hence, the code will look like this:

We left the stroke-dashoffset at 25, so the green sector starts at the top and goes clockwise, overlapping the first sector (pink).


Obviously, this is not exactly what we wanted. We want the fifteenth percent (green) to fit close to the space left by the eighty-fifth percent (pink). We can adjust the stroke-dashoffset until we're lucky, but it wouldn't be so easy if we had two more sectors. Instead, we need a formula:

Circle - total length of all previous sectors + offset of the first sector = offset of the current sector

Plugging in our numbers, we get:


Add more slices to our diagram!

This same formula works for adding additional sectors. Let's fill the chart with 40, 30, 20 percent and the remaining 10 will not be used.

Result:


Adding text to the inside of the chart

It wouldn't be a donut chart without text in and out; that's what the hole is for, right? Well, adding text is easy. We just use the element which is native to SVG shapes.

10 Beers

You will notice that I have split the chart text into 2 elements and grouped them ( ). This was done so that we can more easily overlay the title and number on top of each other, and also arrange them as one unit. I adjusted the X and Y attributes to start at the center of the shape on the base line and align them to the left.


As you can see, the positioning is not quite right, so we need to decorate it with a bit of CSS:

First, let's add the Montserrat font (just because I like it). Then we need to adjust the font-size and line-height. After adding "translateY" in 0.25em, the text is vertically aligned a bit, but we're not done yet.

We need to make both text boxes smaller and center aligned by adjusting the font-size wherever we like (0.6em for the larger number and 0.2em for the title looks fine) and using the "text-anchor" property with the value " middle ".

The text is now centered. All that's left is to make it all uppercase (this is easy) and arrange its individual elements using "translateY" so they fold properly. And this is what we have now:


Accessibility issues

As I mentioned earlier, SVG content is part of the DOM, so it's inherently more accessible. This makes it incredibly easy to provide additional context for screen readers through attributes and elements such as headings.

The first level of accessibility concerns is to make the SVG diagram more semantic by wrapping it in an element

(as this is a diagram). As a shape, we can use the element to provide a title or description for the donut chart.

In addition, we can add content tags and <desc>(which are native to SVG) and associate them with ARIA headers, IDs, and the role of "providing more context for screen readers".</p><p> <style> @import url(https://fonts.googleapis.com/css?family=Montserrat:400); body { font: 16px/1.4em "Montserrat", Arial, sans-serif; } * { -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; } .chart-text { /*font: 16px/1.4em "Montserrat", Arial, sans-serif;*/ fill: #000; -moz-transform: translateY(0.25em); -ms-transform: translateY(0.25em); -webkit-transform: translateY(0.25em); transform: translateY(0.25em); } .chart-number { font-size: 0.6em; line-height: 1; text-anchor: middle; -moz-transform: translateY(-0.25em); -ms-transform: translateY(-0.25em); -webkit-transform: translateY(-0.25em); transform: translateY(-0.25em); } .chart-label { font-size: 0.2em; text-transform: uppercase; text-anchor: middle; -moz-transform: translateY(0.7em); -ms-transform: translateY(0.7em); -webkit-transform: translateY(0.7em); transform: translateY(0.7em); } figure { display: flex; justify-content: space-around; flex-direction: column; margin-left: -15px; margin-right: -15px; } @media (min-width: 768px) { figure { flex-direction: row; } } .figure-content, .figure-key { flex: 1; padding-left: 15px; padding-right: 15px; align-self: center; } .figure-content svg { height: auto; } .figure-key { min-width: calc(8 / 12); } .figure-key { margin-right: 6px; } .figure-key-list { margin: 0; padding: 0; list-style: none; } .figure-key-list li { margin: 0 0 8px; padding: 0; } .shape-circle { display: inline-block; vertical-align: middle; width: 32px; height: 32px; -webkit-border-radius: 50%; -moz-border-radius: 50%; border-radius: 50%; } .shape-fuschia { background-color: #ce4b99; } .shape-lemon-lime { background-color: #b1c94e; } .shape-blue { background-color: #377bbc; } .sr-only { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0,0,0,0); border: 0; } </style> <figure> <div class="figure-content"> <svg width="100%" height="100%" viewBox="0 0 42 42" class="donut" aria-labelledby="beers-title beers-desc" role="img"> <title id="beers-title">Beers in my cellar Belgian Quadrupels Pink chart segment spanning 40% of the whole, which is 4 Belgian Quadrupels out of 10 total. Imperial india pale ales Green chart segment spanning 20% ​​of the whole, which is 2 Imperial India Pale Ales out of 10 total. Russian Imperial Stouts Blue chart segment spanning 3% of the whole, which is 3 Russian Imperial Stouts out of 10 total. 10 Beers

Donut chart showing 10 total beers. Two beers are Imperial India Pale Ales, four beers are Belgian Quadrupels, and three are Russian Imperial Stouts. The last remaining beer is unlabeled.

We can also add the legend key for the chart as part

, noting it with the "view" role and the aria-hidden attribute, since it's really needed for clarity.

With a pinch of magic CSS Flexbox we can position the key to the right and align it vertically with the diagram. What the final product will give us:


Since the CSS design with the key to which it applies border-radius property and Flexbox could be separate articles (the second requires a much longer explanation), I'll leave those topics for later.

End results

As I mentioned earlier, writing the code for SVG objects by hand can be time-consuming, especially when you consider the fact that there are many excellent JavaScript libraries that will build these objects for you. But there may be cases (like my situation) where you or your team need a method that doesn't touch JavaScript, one that will be compiled on the server side.

The good news is that once you get the hang of it in a similar way, it can be applied by you anywhere else with minimum cost effort. Plus, getting your hands dirty with SVG objects is good way learn more about how they work and learn the benefits of using them.

My results:

  • Applying math to something like this is much more fun than it was in high school.
  • In hindsight, I understand that the logic behind stroke-dasharray and stroke-dashoffset is not as complex as I originally thought.
  • Don't forget to add here additional levels availability. After all, accessibility isn't just for the sake of screen readers. It is also needed to make your content more accessible and consumable by all people and all devices (including search engines). If your JavaScript library does not have accessibility functions, consider changing it.

Top related articles