How to rotate darkmode/lightmode button more than once using Javascript - javascript

I'm trying to set up a div with an image background as the selector for darkmode/daymode. The only problem seems to be how to rotate the image 180degree on click so that it displays the daysky when darkmode is selected and rotate it 180degrees to the nightsky when lightmode is selected.
My HTML:
<div id="selector" class="selector"></div>
the CSS (bg image is a circle. The sun and sunrays to the left. To the right the moon and stars. :
height: 3rem;
width: 3rem;
border: 1px solid lightgrey;
margin: 5rem auto;
background-image: url('https://cdn1.vectorstock.com/i/1000x1000/32/25/day-and-night-icon-isolated-on-background-vector-21083225.jpg');
background-size: 120%;
background-repeat: no-repeat;
background-position: center, center;
border-radius: 50%;
/* rotate 90deg sets the background image with the night sky on top part of the image*/
transform: rotate(-90deg);
cursor: pointer;
The 90deg rotation puts the image with the darksky on top (ergo: ready for darkmode selection).
JS:
const elem = document.getElementById('selector');
elem.addEventListener('click', spin);
function spin() {
elem.style.transform = "rotate(180deg)";
}
On the first click of the image it rotates the div 180deg, but based on its original position not on the 90deg rotation done with the CSS. I can work around that. The problem is any subsequent clicking of the image will no longer rotate it because the transform property for that element is already rotate(180deg);

For the first rotation, rotate by 90 degrees. Then each subsequent one rotate 180 degrees from the previous click, using a variable in the outer scope.
By using
deg = (deg + 180) % 360
you keep the variable alternating between 90 and 270. The 270 degree rotation is the same as your -90 degree initial rotation.
const elem = document.getElementById('selector');
elem.addEventListener('click', spin);
var deg = 90
function spin() {
elem.style.transform = `rotate(${deg}deg)`;
deg = (deg + 180) % 360
}
.selector {
height: 3rem;
width: 3rem;
border: 1px solid lightgrey;
margin: 5rem auto;
background-image: url('https://cdn1.vectorstock.com/i/1000x1000/32/25/day-and-night-icon-isolated-on-background-vector-21083225.jpg');
background-size: 120%;
background-repeat: no-repeat;
background-position: center, center;
border-radius: 50%;
/* rotate 90deg sets the background image with the night sky on top part of the image*/
transform: rotate(-90deg);
cursor: pointer;
}
<div id="selector" class="selector" style='background-image: url("https://cdn1.vectorstock.com/i/1000x1000/32/25/day-and-night-icon-isolated-on-background-vector-21083225.jpg")'></div>

Related

How to fix flickering animation in css / javascript

I want to set a scale and a margin of an element to make it centered in a fluid way by using wheel event.
I want to use margins for centering as at some point I would like to set scroll position on wrapping element in fluid way as well.
As you can see in jsfiddle example I'm using css transition attribute to make it fluid.
At the same time I'm changing a scale and a margin but it looks like margin animation kicks in faster leading to moving the div side ways first. You can try it with greater zoom and do mousewheel up and down.
How to fix it so it starts and ends simultanously so the cross located in the middle of the picture doesn't move sideways during zooming in and out?
jsfiddle
<html>
<div id="wrap">
<div id="el">
+
</div>
</div>
</html>
var scale = 1;
var $wrap = $('#wrap');
var $el = $('#el');
$(function() {
$el.on('wheel', function (e) {
scale = e.originalEvent.wheelDelta > 0 ? scale * 1.5: scale / 1.5;
e.preventDefault();
var l = ($wrap.width() - $el.width() * scale) / 2;
var t = ($wrap.height() - $el.height() * scale) / 2;
$el.css({
'transform': "scale(" + scale + ")",
'margin-top': t + "px",
'margin-left': l + "px",
});
});
});
#wrap {
position: fixed;
width: 400px;
height: 300px;
background: pink;
}
#el {
position: relative;
width: 200px;
height: 200px;
text-align: center;
line-height: 200px;
transition: 1s;
transform-origin: 0 0;
background-image: radial-gradient(circle at 0px 0px, #666 1px, transparent 0);
background-size: 4px 4px;
}
Edit: The best way to see the issue is to use mouse scroll once (one tick) and at the end of animation scroll it once again.
Edit2: So I've used Gabriele Petrioli answer and it looks good, however I still needs this info about position of the element. I came up with solution where I 'move'd margins to css transform attribute as 'translate' option and it looks working ok
I've replaced:
$el.css({
'transform': "scale(" + scale + ")",
'margin-top': t + "px",
'margin-left': l + "px",
});
with:
$el.css({
'transform': "translate(" + t + "px, " + l + "px) scale(" + scale + ")",
});
jsfiddle
I would use absolute positioning and position it at the center from the start.
Some changes
use position:absolute and left/right to position it in the center
use transform: translate(-50%, -50%) to match the grid center with the wrapper center
set the origin to 50% 50% as well so you do not have to account for movement
now that you do not need the margins, you can just adjust the scale
added a Math.max/Math.min in there just to keep the example sane for testing.
var scale = 1;
var $wrap = $('#wrap');
var $el = $('#el');
$(function() {
$el.on('wheel', function(e) {
e.preventDefault();
scale = e.originalEvent.wheelDelta > 0 ? scale * 1.5 : scale / 1.5;
scale = Math.min(Math.max(scale, 0.2) ,20);
$el.css({
'transform': `translate(-50%,-50%) scale(${Math.max(scale,0.1)})`,
});
});
});
#wrap {
position: fixed;
width: 400px;
height: 300px;
background: pink;
}
#el {
position: absolute;
width: 200px;
height: 200px;
text-align: center;
line-height: 200px;
transition: transform 1s;
transform-origin: 50% 50%;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-image: radial-gradient(circle at 0px 0px, #666 1px, transparent 0);
background-size: 4px 4px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<html>
<div id="wrap">
<div id="el">
+
</div>
</div>
</html>

I am a issue with jQuery move element according to mouse pointer move

I am trying to do something like when the mouse will moves left to right or right to left the middle will move according to the mouse pointer inside the circle. but I can't. here is my code
circle size 180deg
more reference here is the image
$(document).on("click mousemove", ".circle", function (e) {
var x = e.clientX;
var y = e.clientY;
var angel = Math.round(Math.atan2(x, y) * (180 / Math.PI))
$(".needle").css("transform", "rotate(" + angel + "deg)");
});
#needle {
width: 6px;
height: 83px;
background: red;
transform-origin: bottom;
transition: transform 0.3s;
transform: rotate(345deg);
box-sizing: border-box;
margin-left: -3px;
position: absolute;
left: 116px;
top: 44px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="circle">
<div id="needle" class="needle"></div>
</div>

How to convert this unrecognizable CSS feature into javascript?

I have this problem where I am trying to move a CSS image in correspondence to time but can not use it because it is in CSS. The feature is not the sun, but that yellowish half-circle animation that can be seen in this pen. I am trying to apply that half circle to a completely random shape.
For instance, if the shape is completely random and is on a white canvas and there is a random deformed circle in the middle, then how to fill that circle with the same animation as seen in this pen and how to convert that CSS to javascript or how to control the CSS, because it has to stop and move when certain values are set in.
I do not expect someone to do the whole thing, but rather maybe assist on where I should start when I need to use that yellowish feature as seen in that pen.
Thank you.
Here is the thing.
<div class="sunmoon">
<h2>Sun & Moon</h2>
<div class="sun-times">
<div class="sun-path">
<div class="sun-animation"></div>
</div>
<div class="sun-symbol-path"><span class="symbol">☀</span></div>
</div>
<div class="legend">
<div class="sunrise">05:30 AM</div>
<div class="sunset">8:04 PM</div>
</div>
<div class="clear"> </div>
</div>
<div class="controls">
<button class="start">Start</button>
<button class="reset">Reset</button>
</div>
#import "compass/css3";
$arc-diameter: 170px;
.sunmoon {
position: relative;
& > div {
margin-left: 10px
}
}
.sun-times {
margin-top: 40px;
width: 230px;
height: 60px;
border-bottom: 1px solid #999;
overflow-y: hidden;
.sun-path {
margin-left: 25px;
width: $arc-diameter;
height: $arc-diameter;
overflow: hidden;
border: 1px dashed #999;
border-radius: 50%;
}
.sun-symbol-path {
position: absolute;
color: yellow;
text-shadow: 0 0 5px black;
height: $arc-diameter / 2;
-webkit-transition: -webkit-transform 2s linear;
-webkit-transform-origin: 50% 100%;
-webkit-transform: rotateZ(-75deg);
left: ($arc-diameter / 2) + 25px;
bottom: 0;
.symbol {
position: relative;
font-size: 16px;
top: -8px;
}
}
.sun-animation {
width: 0px;
height: 150px;
background-color: rgba(255, 255, 0, 0.4);
-webkit-transition: width 2s linear;
transition: width 2s linear;
}
}
.legend {
position: absolute;
bottom: 1em;
& > div {
position: absolute;
font-size: 12px;
width: 80px;
}
.sunrise {
left: 15px;
}
.sunset {
left: 185px;
}
}
body {
background-image: url(foo);
background-color: #ccc;
font-family: Helvetica, Sans serif;
h2 {
font-size: 20px;
}
}
.controls {
margin-top: 50px;
}
$('.start').click(function () {
$('.sunmoon .sun-animation').css('width', '70%');
$('.sun-symbol-path').css('-webkit-transform', 'rotateZ(27deg)');
// TODO: mention that this isn't nice
// city.find('.sunmoon .sun-animation').css('-webkit-transform', 'scaleX(50)');
return false;
});
$('.reset').click(function () {
$('.sun-animation').css('width', '0%');
$('.sun-symbol-path').css('-webkit-transform', 'rotateZ(-75deg)');
return false;
});
You can achieve it creating a shape in Illustrator with the inside transparent and the outside in the color that you want, and setting another box (with a new color, in this case yellow, and the same width of the shape), underneath that shape (e.g. using z-index) with position:absolute and left:-100%, and onClick, start and stop the transition to right.
I'll recommend you to use GSAP TimeLineMax. It lets you play and stop the transition with its functions, e.g.:
//off course after document load.
let animation = new TimelineMax();
animation
.to(
".underneath-box", //box class
10, //seconds
{
left:"100%", //100% of the width
ease: Power4.easeInOut //ease effect.
});
animation.pause(); //To prevent start.
$('start-button').click(function(){ //on start button click
animation.play().timeScale(1); //start animation
});
$('reset-button').click(function(){ //on reset button click
animation.reverse().timeScale(2); //reverse the entire animation
});
I'm assuming that you know some Html, and css basics. Don't forget to create those divs and buttons with its classes. Cheers.
Well, I had some fun figuring this one out. Not sure that's what you wanted but it's what I've got. Plain JS.
var c1 = document.getElementById("canvas1");
var c2 = document.getElementById("canvas2");
var ctx = c1.getContext("2d");
ctx.beginPath();
ctx.arc(100, 100, 90, 0, 2 * Math.PI);
ctx.lineWidth = 2;
ctx.stroke();
animateCanvas();
function animateCanvas(){
var w = 0;
var timer = setInterval(function(){
c2.width = w;
w += 1;
var ctx = c2.getContext("2d");
ctx.beginPath();
ctx.arc(100, 100, 89, 0, 2 * Math.PI);
ctx.fillStyle = "#efba32";
ctx.fill();
if (w===200){clearInterval(timer)}
}, 20);
}
.canvases{
position: absolute;
top: 0;
left: 0;
}
<canvas id="canvas1" class="canvases" width="200" height="200"></canvas>
<canvas id="canvas2" class="canvases" width="200" height="200"></canvas>
The example you've attached uses two divs, and outer and an inner, to create this effect. The outer div has a border radius property to make it look like a half circle. The inner div is a normal rectangle with overflow set to hidden. So the script creates the optical illusion of wiping to the right by animating the width of the inner div going from 0% of the outer div to 70%. To make this illusion work with a polygon, you would need to use something like clip-path instead of border-radius.
Here is an example of an arbitrary polygon, that will wipe right with a different background color. HTML:
<div>
<div class="outer"><div class="inner"></div></div>
</div>
CSS:
.outer {
margin-left:200px;
background-color: lightgray;
width: 300px;
height: 100px;
display: block;
overflow: hidden;
-moz-clip-path: polygon(0px 0px, 300px 0px, 300px 300px);
-webkit-clip-path: polygon(0px 0px, 300px 0px, 300px 300px);
clip-path: polygon(0px 0px, 300px 0px, 300px 300px);
}
.inner {
background-color: red;
width :0;
height: 300px;
display: block;
}
jQuery:
$('.outer').click(function() {
$('.inner').animate({width:"150px"}, 1800)
});
Here is a working fiddle: https://jsfiddle.net/r93pocgt/
My implementation uses jQuery's animate to change the CSS property for width, when you click on the outer div. I've done my best to simplify it to make it clear what's doing what.

Half circle gradient js

How to get the gradient effect in the circle? I have such an initial code:
HTML:
<div class="progresss">
<div class="barOverflow">
<div class="bar"></div>
</div>
<span>10</span>%
</div>
<div class="progresss">
<div class="barOverflow">
<div class="bar"></div>
</div>
<span>75</span>%
</div>
SCSS:
.progresss{
position: relative;
margin: 4px;
float:left;
text-align: center;
}
.barOverflow{ /* Wraps the rotating .bar */
position: relative;
//overflow: hidden; /* Comment this line to understand the trick */
width: 145px; height: 45px; /* Half circle (overflow) */
margin-bottom: -14px; /* bring the numbers up */
&:after {
content: '';
position: relative;
display: block;
top: -75px;
width: 145px;
height: 90px;
background-color: #f3f5f6;
}
}
.bar{
position: relative;
top: 0; left: 0;
width: 145px; height: 145px; /* full circle! */
border-radius: 50%;
box-sizing: border-box;
border: 27px solid red; /* half red, */
border-bottom-color: green; /* half green */
border-right-color: green;
}
JS:
$(".progresss").each(function(){
var $bar = $(this).find(".bar");
var $val = $(this).find("span");
var perc = parseInt( $val.text(), 10);
$({p:0}).animate({p:perc}, {
duration: 3000,
easing: "swing",
step: function(p) {
$bar.css({
transform: "rotate("+ (45+(p*1.8)) +"deg)", // 100%=180° so: ° = % * 1.8
// 45 is to add the needed rotation to have the green borders at the bottom
});
$val.text(p|0);
}
});
});
what I want is:
I did something similar back in the day and as I discovered that only way to implement gradient border was (and I guess still is) using CSS border-image property, I came up with completely different approach:
Create 3 nested div elements:
wrapper, which we need to hide the overflow,
out, which is the one with gradient background color - that's the one we are going to rotate,
in, which is the inner circle on which growing percentage numbers are displayed,
Inside first wrapper add some element to hold the percentage number and using position: absolute, place it in the middle of the parent: we do not display percentage in the in element, because it is rotating with out one, and it's easier to just create another element than synchronize rotation of two circles.
Make wrapper a circle and hide it's overflow - it helps in 4.:
Give out element gradient background, bottom half green-ish, top half transparent - it is shaped as circle due to it's parent overflow.
Whole the rest is just math: you can check it out in my fiddle.
It is not perfect solution and I would not mind posting it in case where you used percentage width and height. But, as I saw fixed (px) dimensions I thought that you can use my approach as well.
It is all matter of adjusting it to your needs - gradient as well as dimensions, and if you have trouble positioning the whole thing, just do it with wrapper element, and children will "follow".

div as Circle Showing percentage at the Middle javascript

I Have a div as a circle, with the inner text showing values as percentage say(20%). The problem is the inner text is not displaying exactly at the center of the circle.
The inner text is a dynamic value based on some results in percentage. The radius of the circle is based on the percentage values returned as result.The percentage values returned should be displayed exactly at the center of the circle. Could Someone help me with this.
Thanks.
Heres the code,
<style>
#circle {
border: 1px solid red;
border-radius: 50%;
-moz-box-sizing: border-box;
box-sizing: border-box;
background:blue;
}
</style>
<div id="circle"></div>
<script>
$(function(){
var maxWidth = 500, // This is the max width of your circle
percent = Number($('#result').text()); // This is the percentage value
percent = percent / 100;
$("#circle").css({
"width" : maxWidth * percent,
"height" : maxWidth * percent,
});
circle.innerText =$('#result').text() + "%";
</script>
You can add another DIV inside the circle which holds the text and add position: relative to #circle in the CSS. Also add this:
#circle>* {
position: absolute;
top: 50%;
left: 50%;
-webkit-transform: translateX(-50%) translateY(-50%);
-moz-transform: translateX(-50%) translateY(-50%);
transform: translateX(-50%) translateY(-50%);
}
position: absolute and top: 50% / left: 50% will place the top-left corner of the inner DIV in the middle of the circle. The transform shifts it 50% of its own size to the left/top.
This work out for me.
display: table-cell;
vertical-align: middle;
You can check the fiddle:
http://jsfiddle.net/Pallab/zCfyV/embedded/result/

Categories