CSS pie chart with background pattern [duplicate] - css

This question already has an answer here:
How to create a circular arc (sector) with a background image?
(1 answer)
Closed 2 years ago.
I'm trying to make a pie chart with PNG image as background-image there:
.piebg {
width: 95px;
height: 95px;
border-radius: 50%;
background-image: url('https://pngimg.com/uploads/pizza/pizza_PNG44095.png');
background-size: cover;
}
.pie {
width: 102px;
height: 102px;
border-radius: 50%;
background: inherit;
}
.pie::before {
content: '';
display: block;
margin-left: 50%;
height: 100%;
border-radius: 0 100% 100% 0 / 50%;
background-color: #fff;
transform-origin: left;
animation: spin 5s linear infinite, bg 5s step-end 1;
}
.pie::after {
content: '';
display: block;
height: 100%;
right: 50px;
border-radius: 100% 0 0 100% / 50%;
background-color: #fff;
position: relative;
top: -102px;
}
#keyframes spin {
to {
transform: rotate(.5turn);
}
}
#keyframes bg {
50% {
background: transparent;
}
}
<div class="piebg">
<div class="pie"></div>
</div>
There is an issue with the wrong fill of a pie chart area.
CSS animation is not a strong side of my experience yet to complete this example.
Could you help me to find an article or example how to complete my pie chart?

If you consider discontinuous animation, we can do this with only single div and mask.
.pie {
width: 95px;
height: 95px;
border-radius: 50%;
background-image: url('https://i.stack.imgur.com/tJMg9.png');
background-size: cover;
--s: 0%;
--mask: conic-gradient(#000 var(--s), transparent var(--s) 360%);
-webkit-mask: var(--mask);
mask: var(--mask);
animation: pie 2s forwards;
/* ↑ you can use "infinite" instead */
}
#keyframes pie {
10% {
--s: 10%;
}
20% {
--s: 20%;
}
30% {
--s: 30%;
}
40% {
--s: 40%;
}
50% {
--s: 50%;
}
60% {
--s: 60%;
}
70% {
--s: 70%;
}
80% {
--s: 80%;
}
90% {
--s: 90%;
}
100% {
--s: none;
}
}
<div class="pie"></div>
Also now we can make a continuous animation with #property
#property --s {
initial-value: 0%;
inherits: false;
syntax: '<percentage>';
}
.pie {
width: 95px;
height: 95px;
border-radius: 50%;
background-image: url('https://i.stack.imgur.com/tJMg9.png');
background-size: cover;
--s: 0%;
--mask: conic-gradient(#000 var(--s), transparent var(--s) 360%);
-webkit-mask: var(--mask);
mask: var(--mask);
animation: pie 2s 1s infinite;
}
#keyframes pie {
100% {
--s: 100%;
}
}
<div class="pie"></div>

Related

How to improve an animated tv static effect using a pure css gradient

How would I be able to improve this animated static noise effect using a css gradient?
CSS only, no javascript, no svg, no image, using only a gradient, and adjusting that.
A tv no signal noise effect is what I am looking for using a css gradient.
Does anyone know how this effect can be improved, made better?
Is there a better way it can be written?
I am looking for something that is more accurate to a tv noise effect.
I think the way this effect is written can be improved.
Are there any tweaks or adjustments that can be made to it to so that it better depicts a tv noise effect?
The gradient can be anything, as long as it is a gradient, it doesn't matter what kind.
This one uses radial gradient:
https://jsfiddle.net/xhdkza5w/
html,
body {
width: 100%;
height: 100%;
display: flex;
}
.tv-static {
width: 500px;
height: 300px;
margin: auto;
background-image: repeating-radial-gradient(circle at 17% 32%, white, black 0.00085px);
animation: back 5s linear infinite;
}
#keyframes back {
from {
background-size: 100% 100%;
}
to {
background-size: 200% 200%;
}
}
<div class="tv-static"></div>
This one uses a conic-gradient: https://jsfiddle.net/bkx50apm/
html,
body {
width: 100%;
height: 100%;
display: flex;
}
.tv-static {
width: 500px;
height: 300px;
margin: auto;
background-image: repeating-conic-gradient(white, black 0.00085%);
animation: back 25s linear infinite;
}
#keyframes back {
from {
background-size: 100% 100%;
}
to {
background-size: 200% 200%;
}
}
<div class="tv-static"></div>
Do you mean this effect?
html,
body {
width: 100%;
height: 100%;
display: flex;
}
.animation {
width: 240px;
height: 240px;
margin: auto;
background-image: repeating-radial-gradient(circle at 17% 32%, white, black 0.00085px);
animation: animation 5s linear infinite;
}
#keyframes animation {
from {
background-position: 0px 0px;
}
to {
background-position: 240px 240px;
}
}
<div class="animation"></div>
Or this effect?
html,
body {
width: 100%;
height: 100%;
display: flex;
}
.animation {
width: 240px;
height: 240px;
margin: auto;
background-image: repeating-radial-gradient(circle at 17% 32%, white, black 0.00085px);
background-position: center;
animation: back 5s linear infinite;
}
#keyframes back {
from {
background-size: 100% 100%;
}
to {
background-size: 200% 200%;
}
}
<div class="animation"></div>
Edit: Added background-position: center.
By overlaying 2 of those effect on top of each other and each div has a different animation, you can create interference between the two that removes the artifacts of only having 1 static noise made from a single div.
This might be improved as I'm not well versed in css but the proof of concept works
html,
body {
width: 100%;
height: 100%;
display: flex;
}
.container_row {
display: flex;
}
.layer1 {
width: 100%;
background-color: rgba(255, 255, 255, 0.5);
}
.layer2 {
width: 100%;
margin-left: -100%;
background-color: rgba(255, 255, 255, 0.5);
}
.tv-static {
width: 500px;
height: 300px;
margin: auto;
background-image: repeating-radial-gradient(circle at 17% 32%, white, black 0.00085px);
}
.animation1 {
animation: back1 1s linear infinite;
}
.animation2 {
animation: back2 0.1s linear infinite;
}
#keyframes back1 {
from {
background-size: 100% 100%;
}
to {
background-size: 99% 100%;
}
}
#keyframes back2 {
from {
background-size: 48.56% 50%;
}
to {
background-size: 43.9% 50.1%;
}
}
<div class="layer1">
<div class="tv-static animation1"></div>
</div>
<div class="layer2">
<div class="tv-static animation2"></div>
</div>
With smooth timing function, animations don't give that effect we need to use step timing function to give those sudden change effect.
Solution 1: I've changed animation. And tweaked your gradient a little bit. I think using gradient is not a reliable solution because browsers do calculations differently and fractions, rounding change output. You are using radial gradient it looks things are going outwards from center of the placement. You'll have to test his on every platform and browser to see if it looks same.
Solution 2: Used SVG instead of gradient. The feTurbulence filter gives the noise effect. You can use svg as background-image.
Solution 3: Used image instead of gradient with same animation. Advantage of using image is that it'll look same across all browsers and screens.
Solution 3: Simply used noise gif image. No animation is required. :)
View following in 'full page' mode:
body {
text-align: center;
}
.tv {
width: 400px;
height: 200px;
border: 6px solid black;
margin: 0 auto;
overflow: hidden;
position: relative;
border-radius: 50% / 10%;
}
.tv-static {
position: absolute;
top: -200px;
left: -200px;
margin: auto;
height: 800px;
width: 800px;
background-image: repeating-radial-gradient(circle at 17% 132%, white 0.0005px, black 0.00085px);
animation: anim 1s steps(2, jump-both) infinite both;
transform: translate3d(0, 0, 0);
}
/******************************/
.tv0 {
width: 400px;
height: 200px;
border: 6px solid black;
margin: 0 auto;
overflow: hidden;
position: relative;
border-radius: 50% / 10%;
isolation: isolate;
}
.tv-static0 {
position: absolute;
top: 0px;
left: 0px;
margin: auto;
height: 300%;
width: 300%;
animation: anim 1s steps(2, end) infinite both;
transform: translate3d(0, 0, 0);
filter: contrast(300%) brightness(50%);
}
.tv-static0 svg {
height: 200%;
width: 100%;
transform: scale(2.5);
}
/******************************/
.tv1 {
width: 400px;
height: 200px;
border: 6px solid black;
margin: 0 auto;
overflow: hidden;
position: relative;
border-radius: 50% / 10%;
}
.tv-static1 {
position: absolute;
top: -500px;
right: -500px;
bottom: -500px;
left: -500px;
margin: auto;
background-image: url(https://i.stack.imgur.com/uzEM4.png);
animation: anim 1s steps(2, end) infinite both;
transform: translate3d(0, 0, 0);
}
/******************************/
.tv2 {
width: 400px;
height: 200px;
border: 6px solid black;
margin: 0 auto;
overflow: hidden;
position: relative;
border-radius: 50% / 10%;
}
.tv-static2 {
position: absolute;
top: -500px;
right: -500px;
bottom: -500px;
left: -500px;
margin: auto;
background-image: url(https://i.stack.imgur.com/9Be02.gif);
transform: translate3d(0, 0, 0);
}
#keyframes anim {
0% {
transform: translateX(0px, 0px);
}
10% {
transform: translate(-100px, 100px);
}
20% {
transform: translate(150px, -100px);
}
30% {
transform: translate(-100px, 100px);
}
40% {
transform: translate(100px, -150px);
}
50% {
transform: translate(-100px, 200px);
}
60% {
transform: translate(-200px, -100px);
}
70% {
transform: translateY(50px, 100px);
}
80% {
transform: translate(100px, -150px);
}
90% {
transform: translate(0px, 200px);
}
100% {
transform: translate(-100px, 100px);
}
}
Your original code. modified. May not work on every browser.
<div class="tv">
<div class="tv-static"></div>
</div>
<br> Using SVG `feTurbulence` filter
<div class="tv0">
<div class="tv-static0">
<svg viewBox="0 0 200% 200%" xmlns='http://www.w3.org/2000/svg'>
<filter id='noiseFilter'>
<feTurbulence type='turbulence' result='noise' baseFrequency='0.7' numOctaves='6' seed='2'
stitchTiles='noStitch' />
</filter>
<rect width='100%' height='100%' filter='url(#noiseFilter)' />
</svg>
<div class="overlay"></div>
</div>
</div>
<br>
<br> Animating image. Color TV
<div class="tv1">
<div class="tv-static1"></div>
</div>
<br> Using gif. No animation.
<div class="tv2">
<div class="tv-static2"></div>
</div>

Form does not rotate around center axis (x,y)

Even though I have set [transform-origin: 100% 50%;] in css, the form does not rotate around its center in comparison to X- and Y- axis.
Question: How can I make the form rotate counted exactly from its midpoint.
.box {
background-color: pink;
margin: 300px 0 0 300px;
width: 200px;
height: 200px;
}
.box {
position: absolute;
animation: spin 10s;
animation-fill-mode: forwards;
}
.line-horizontal {
background-color: black;
width: 200px;
height: 5px;
margin: 100px 0 0 0;
}
.line-vertical {
background-color: black;
width: 5px;
height: 200px;
margin: -105px 0 0 100px;
}
#keyframes spin {
from {
transform:rotate(0deg);
transform-origin: 100% 50%;
}
to {
transform:rotate(360deg);
}
}
<div class="box">
<div class="line-horizontal"></div>
<div class="line-vertical"></div>
</div>
Change the tranform-origin to 50% 50% instead which means the center in both axis and don't put it inside the keyframes because it will get animated
.box {
background-color: pink;
width: 200px;
height: 200px;
}
.box {
position: absolute;
animation: spin 10s;
animation-fill-mode: forwards;
transform-origin: 50% 50%;
/*center*/
}
.line-horizontal {
background-color: black;
width: 200px;
height: 5px;
margin: 100px 0 0 0;
}
.line-vertical {
background-color: black;
width: 5px;
height: 200px;
margin: -105px 0 0 100px;
}
#keyframes spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
<div class="box">
<div class="line-horizontal"></div>
<div class="line-vertical"></div>
</div>
You can also simplify your code like below in case you need the same visual:
.box {
width: 200px;
height: 200px;
background:
linear-gradient(#000,#000) center/100% 5px,
linear-gradient(#000,#000) center/5px 100%,
pink;
background-repeat:no-repeat;
animation: spin 10s forwards;
transform-origin: 50% 50%; /* OR center*/
}
#keyframes spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
<div class="box">
</div>

Simple loading bar

I'm trying to make a simple download bar, but it turns out only a solid color without transition animation.
In addition, the "repeating-linear-gradient" does not work and I cannot understand why.
I am hope for your help. Thank you!
.Download {
height: 80px;
width: 1000px;
border: 2px solid black;
border-radius: 100px;
/*background: repeating-linear-graient (90deg, blue, red, 100px);*/
background: linear-gradient(to left, blue, red);
animation-name: download;
animation-direction: 10s;
animation-timing-function: linear;
animation-direction: normal;
}
#keyframes download {
0% {
left: -100%;
}
100% {
left: 100%;
}
}
<div class="Download">
</div>
You can use pseudo code to achieve this.
.Download {
height: 80px;
width: 1000px;
border: 2px solid black;
border-radius: 100px;
position: relative;
overflow: hidden;
}
.Download:after {
content: "";
position: absolute;
background-image: linear-gradient(to left, blue, red);
width: 100%;
height: 100%;
top: 0;
left: -100%;
animation: download 5s;
}
#keyframes download {
0% {
left: -100%;
}
100% {
left: 0%;
}
}
<div class="Download">
</div>
You need to make half the linear gradient transparent (a bit list to prevent a hole in the end). Set the background position x to 100% to present only the transparent part. Then animation to 0:
.Download {
height: 80px;
width: 1000px;
border: 2px solid black;
border-radius: 100px;
background: linear-gradient(to right, red 0, blue 50.02%, transparent 50.02%) no-repeat;
animation: download 10s forwards;
background-position: 100% 0;
background-size: 200% 100%;
}
#keyframes download {
to {
background-position: 0 0;
}
}
<div class="Download">
</div>

How to stop progress bar animation halfway using Keyframes

I'm trying to load the progress bar up to a certain percentage. Whatever that percentage is, the progress bar will stop at that specific color animation specified in the keyframes.
How can i get it to work.
HTML
<div class="container">
<div class="progress-bar">
<span style="width:50%">
<span class="progress-value"></span>
</span>
</div>
<span><strong>CSS</strong></span>
<br/>
</div>
CSS
.container {
display: flex;
justify-content: center;
}
.progress-bar {
background-color: lightgray;
border-radius: 1.25em;
width: 300px;
height: 16px;
width: 50vw;
}
.progress-bar > span {
display: flex;
}
.progress-value {
background-color: #673ab7;
transition: 0.3s all linear;
border-radius: 1.25em;
height: 16px;
width: 50vw;
animation: progress-color 3s linear forwards;
-webkit-animation: progress-color 3s linear forwards;
}
/* animation */
#keyframes progress-color {
0% {
width: 0;
}
50% {
width: 30%;
background: purple;
}
100% {
background: green;
width: 100%;
}
}
#-webkit-keyframes progress-color {
0% {
width: 0;
}
50% {
width: 30%;
background:red;
}
100% {
background: green;
width: 100%;
}
}
Here's my codepen
https://codepen.io/mingsterism/pen/xJgePK
The problem is that where you have specified the animation is 100% completed under the #keyframes , there you must specify red as the color, which you have specified as the color you wish when the bar reaches 50%, while the rest of of the code is fine. Replace your piece of code with this one below and tell, is this what you want ?
#keyframes progress-color {
0% {
width: 0;
}
50% {
width: 30%;
background: green;
}
100% {
background: red;
width: 100%;
}
}
#-webkit-keyframes progress-color {
0% {
width: 0;
}
50% {
width: 30%;
background: green;
}
100% {
background: red;
width: 100%;
}
}

How to scale (transform) div in width and height without scaling border width?

#keyframes scale {
0% {
transform: scale(0);
}
100% {
transform: scale(5);
}
}
div#scale {
width: 10px;
height: 10px;
border: 1px solid;
border-radius: 50%;
animation: scale 5s infinite;
}
<div id="scale"></div>
How to scale (transform) div in width and height without scaling border width? I'm trying to build this effect.
As for the workaround / alternative you can just animate its width and height:
body {padding:50px}
#scale {
border: 1px solid;
border-radius: 50%;
animation: scale 3s linear infinite;
position: relative;
top: 0;
left: 0;
}
#keyframes scale {
0% {
width: 0;
height: 0;
}
100% {
width: 50px;
height: 50px;
top: -25px;
left: -25px;
}
}
<div id="scale"></div>
To make it grow from the center use negative margins / values for the top and left properties equal to half of the change in size, so in this case that's -25px.
One option you have is to use synced elements. One that scales and another one, empty, that changes size while keeping border-width. The other element I used is the ::after of a wrapper.
#keyframes scale-div {
0% {
transform: scale(0);
}
50% {
transform: scale(1)
}
100% {
transform: scale(0);
}
}
#keyframes scale-border {
0% {
width: 0px;
height: 0px;
}
50% {
width: 100px;
height: 100px;
}
100% {
width: 0px;
height: 0px;
}
}
.scale {
animation: scale-div 5s steps(300, end) infinite ;
transition-timing-function: cubic-bezier(.4,0,.2,1);
background-color: rgba(0,0,0,.05);
border-radius: 50%;
}
.scale,.scale-wrapper {
width: 100px;
height: 100px;
}
.scale-wrapper {
position: relative;
}
.scale-wrapper::after {
position: absolute;
border-radius: 50%;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
border: 1px solid black;
width: 98px;
height: 98px;
animation: scale-border 5s steps(300, end) infinite;
transition-timing-function: cubic-bezier(.4,0,.2,1);
content: '';
}
<div class="scale-wrapper">
<div class="scale"></div>
</div>
There are ton of problems with scaling transforms since it's ratio based. if you scale it, it's going to scale its layout, border even :after, :before elements and all children.
For what you're trying to do it's best if you just use svg. Svg circle element's radius property can be animated. I suggest you run browser support test on it; However, svg support is pretty wide especially with animations.
svg .circle {
cx: 50%;
cy: 50%;
r: 20px;
stroke: #dfdfdf;
stroke-width: 2px;
transform: translateZ(0);
fill: none;
animation: ping 2s infinite;
}
#keyframes ping {
from {
r: 10px;
}
to {
r: 40px;
}
}
<svg><circle r="20px" class="circle"/></svg>
#keyframes scale {
0% {
transform: scale(0); border: 1px solid;
}
100% {
transform: scale(5); border: 5px solid;
}
}
div#scale {
width: 10px;
height: 10px;
border-radius: 50%;
animation: scale 5s infinite;
}
did you try above code ?

Resources