Recalculate transform origin on a scaled element - javascript

I have an element which has to be scaled from 100px from the left while already having a scale of 0.5. When transforming the origin it is on 50px on the left side and scaling from the wrong side of the line.
When scaling the element I want it to scale from the purple line. Without using the left CSS property.
I tried to use this formula but it was slightly off:
x + (x * scale)
* {
margin: 0;
padding: 0;
}
.box {
position: relative;
width: 100px;
height: 100px;
margin-top: -10px;
}
.example-initial {
background: blue;
transform: scale(0.2);
transform-origin: 100px 0px;
}
.example-wrong {
background: green;
transform: scale(0.5);
transform-origin: 100px 0px;
}
.example-right {
background: red;
transform: scale(0.5);
transform-origin: 200px 0px;
}
.transform-origin-line-example {
position: absolute;
left: 100px;
width: 1px;
height: 200px;
background: purple;
top: 0;
}
<div class="example-initial box"></div>
<div class="example-wrong box"></div>
<div class="example-right box"></div>
<div class="transform-origin-line-example"></div>

The formula you're looking for is:
(x * (1 / (1 - 0.1));
x is the left position.
1 is the full scale.
0.1 is the used scale.
* {
margin: 0;
padding: 0;
}
.box {
position: relative;
background: red;
width: 100px;
height: 100px;
transform: scale(0.1);
transform-origin: calc(100px * (1 / 0.9)) 0px;
}
.example-box {
position: relative;
background: blue;
width: 100px;
height: 100px;
transform: scale(0.5);
transform-origin: calc(100px * (1 / 0.5)) 0px;
}
.transform-origin-line-example {
position: absolute;
left: 100px;
width: 1px;
height: 200px;
background: green;
top: 0;
}
<div class="box"></div>
<div class="example-box"></div>
<div class="transform-origin-line-example"></div>

You can just fix the transform-origin code as
transform: scale(-0.5);

Related

Create a Button that's border incrementally diminishes onClick and fires an event on time '0'

I found this great tool but it's awkward to implement in my project: https://github.com/vydimitrov/react-countdown-circle-timer
I want to create a reusable button component that onClick, starts a similar countdown effect with its border, giving the user a chance to 'undo' their decision (similar to forwarding a message in fb messenger). I can figure out the react logic but no clue where to start with css
Thanks in advance
Browsing the code of the component you mention, I noticed it uses an SVG element with animated stroke to create and animate the circular progress bar.
This article is my favourite one about this specific problem:
https://css-tricks.com/building-progress-ring-quickly/
Here is the code from that article for future reference. This is not my code, kudos to the original author of the article:
var circle = document.querySelector('circle');
var radius = circle.r.baseVal.value;
var circumference = radius * 2 * Math.PI;
circle.style.strokeDasharray = `${circumference} ${circumference}`;
circle.style.strokeDashoffset = `${circumference}`;
function setProgress(percent) {
const offset = circumference - percent / 100 * circumference;
circle.style.strokeDashoffset = offset;
}
const input = document.querySelector('input');
setProgress(input.value);
input.addEventListener('change', function(e) {
if (input.value < 101 && input.value > -1) {
setProgress(input.value);
}
})
html, body {
background-color: #2962FF;
display: flex;
align-items: center;
justify-content: center;
height: 100%;
position: relative;
}
.progress-ring {
}
.progress-ring__circle {
transition: 0.35s stroke-dashoffset;
// axis compensation
transform: rotate(-90deg);
transform-origin: 50% 50%;
}
input {
position: fixed;
top: 10px;
left: 10px;
width: 80px;
}
<svg
class="progress-ring"
width="120"
height="120">
<circle
class="progress-ring__circle"
stroke="white"
stroke-width="4"
fill="transparent"
r="52"
cx="60"
cy="60"/>
</svg>
<input
value="35"
type="number"
step="5"
min="0"
max="100"
placeholder="progress"
>
This is a pure css pie timer which looks pretty similar to one of your timers mentioned in the link.
See it in full screen
var time = 11;
{
var func = setInterval(function() {
if (time != 0) {
document.getElementsByClassName('time')[0].innerHTML = time;
time--;
if (time < 5) {
document.getElementsByClassName('warning')[0].style.display = "block";
}
} else {
document.getElementsByClassName('time')[0].innerHTML = "0";
document.getElementsByClassName('warning')[0].style.display = "none";
clearInterval(func);
}
}, 1000);
}
.timer {
height: 200px;
width: 200px;
border-radius: 50%;
background-color: black;
animation: time 5s infinite;
margin-left: 570px;
margin-top: 200px;
}
.bar {
position: absolute;
}
.left_progress {
position: absolute;
height: 200px;
width: 200px;
background: linear-gradient(90deg, #00d2ff 0%, #3a47d5 100%);
border-radius: 50%;
clip: rect(0px 100px 200px 0px);
animation: rotate_right 6s 6s linear both;
}
#keyframes rotate_right {
100% {
transform: rotateZ(180deg);
}
}
.left_progress_bar {
position: absolute;
height: 200px;
width: 200px;
background-color: #E9E9E9;
border-radius: 50%;
clip: rect(0px 100px 200px 0px);
z-index: 1;
animation: mid-way 4s linear both;
}
.right_progress {
position: absolute;
height: 200px;
width: 200px;
background-color: #E9E9E9;
border-radius: 50%;
clip: rect(0px 100px 200px 0px);
transform: rotateZ(180deg);
animation: rotate_left 6s linear both;
}
#keyframes rotate_left {
100% {
transform: rotateZ(360deg);
}
}
.right_progress_bar {
position: absolute;
height: 200px;
width: 200px;
background: linear-gradient(90deg, #00d2ff 0%, #3a47d5 100%);
border-radius: 50%;
clip: rect(0px 100px 200px 0px);
transform: rotateZ(180deg);
z-index: 1;
}
.main_content {
position: absolute;
height: 180px;
width: 180px;
border-radius: 50%;
background-color: white;
z-index: 4;
margin-top: 10px;
margin-left: 10px;
font-family: 'arial';
text-align: center;
}
.timer_content {
position: absolute;
margin-top: 40px;
margin-left: 45px;
}
.content {
font-size: 15px;
margin: 0px;
color: #6B6C6D;
}
.time {
font-size: 55px;
margin: 0px;
background: -webkit-linear-gradient(90deg, #00d2ff 0%, #3a47d5 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.warning {
position: absolute;
height: 180px;
width: 180px;
border-radius: 50%;
background-color: #DBDBDB;
animation: warning_bell 1s infinite;
display: none;
}
#keyframes warning_bell {
from {
transform: scale(0);
opacity: 1;
}
to {
transform: scale(1);
opacity: 0;
}
}
<div class="timer">
<div class="right_progress_bar">
<div class="right_progress"></div>
</div>
<div class="left_progress_bar">
<div class="left_progress"></div>
</div>
<div class="main_content">
<div class="warning"></div>
<div class="timer_content">
<p class="content">You can do in</p>
<p class="time">12</p>
<p class="content">seconds</p>
</div>
</div>
</div>

How to repeat a circle across browser width

I created the circle with css and html and I want to have it repeat across the x-dimension of the browser (trying to replicate the image shown below). I know there's background-image: x-repeat, but this isn't a background image, so I cant use that and there will also be content inside the circle. I was originally trying to create 9 circles, then absolutely position them, but I realized that it may not be the best way and won't work if the browser shrinks. Then remembered the repeat-x property. Here's my code of my original line of thinking:
HTML Code
<div class="circles">
<div id="half-circle1"></div>
<div id="circle1"></div>
<div id="circle2"></div>
<div id="circle3"></div>
<div id="circle4"></div>
<div id="circle5"></div>
<div id="circle6"></div>
<div id="circle7"></div>
<div id="half-circle2"></div>
</div><!-- end of circles -->
CSS Code
.circles div { width: 199px; height: 199px; background-color: #60c5ca; -moz-border-radius: 100px; -webkit-border-radius: 100px; border-radius: 100px; position: absolute; top: 0; left: 0; }
#half-circle1 { top: 255px; left: 0px;; width: 100px; border-radius:0 100px 100px 0; opacity: 0.6;}
#half-circle2 { top: 0; left: 0; width: 100px; border-radius: 100px 0 0 100px; opacity: 0.6; }
#circle1 { top: 235px; left: 50px; opacity: 0.5; }
#circle2 { top: 285px; left: 200px; opacity: 0.6; }
#circle3 { top: 235px; left: 300px; opacity: }
#circle4 { top: 235px; left: 300px; opacity: }
#circle5 { top: 235px; left: 300px; opacity: }
#circle6 { top: 235px; left: 300px; opacity: }
#circle7 { top: 235px; left: 300px; opacity: }
You can utilize css calc() with vw, vh units
.circles div {
width: 199px;
height: 199px;
background-color: #60c5ca;
-moz-border-radius: 100px;
-webkit-border-radius: 100px;
border-radius: 100px;
position: absolute;
top: 0;
left: 0;
}
#half-circle1 {
top: 255px;
left: calc(0vw);
width: 100px;
border-radius: 0 100px 100px 0;
opacity: 0.6;
}
#half-circle2 {
top: 235px;
left: calc(90vw + 50px);
width: 100px;
border-radius: 100px 0 0 100px;
opacity: 0.6;
}
#circle1 {
top: 235px;
left: calc(10vw - 50px);
opacity: 0.5;
}
#circle2 {
top: 285px;
left: calc(20vw);
opacity: 0.6;
}
#circle3 {
top: 235px;
left: calc(30vw);
opacity: 0.7;
}
#circle4 {
top: 235px;
left: calc(40vw);
opacity: 0.5;
}
#circle5 {
top: 235px;
left: calc(50vw);
opacity: 0.5;
}
#circle6 {
top: 235px;
left: calc(60vw + 50px);
opacity: 0.6;
}
#circle7 {
top: 235px;
left: calc(70vw + 100px);
opacity: 0.7;
}
<div class="circles">
<div id="half-circle1"></div>
<div id="circle1"></div>
<div id="circle2"></div>
<div id="circle3"></div>
<div id="circle4"></div>
<div id="circle5"></div>
<div id="circle6"></div>
<div id="circle7"></div>
<div id="half-circle2"></div>
</div>
jsfiddle https://jsfiddle.net/Lu1xwkre/1/

See through dark overlay css and jquery

I'm doing a site with a "hidden" image. I hide the image using a dark overlay, but now I want the cursor to see through the dark overlay.
An almost working example is here: https://jsfiddle.net/swx5x38j/
What I want to know is, how I make the light div look through the dark overlay div. Is this somehow possible, or should I go for different solution? And does some have a hint on such one?
The code follows here as well. First the CSS:
* {
margin: 0;
padding: 0;
}
#image {
background: url(https://placeimg.com/640/480/animals) center no-repeat;
width: 800px;
height: 600px;
}
#overlay {
opacity: 0.9;
background: #000;
width: 100%;
height: 100%;
top: 0;
left: 0;
position: fixed;
}
#light {
opacity: 1;
top: 50%;
left: 50%;
width: 100px;
height: 100px;
border-radius: 50%;
position: absolute;
background: #fff;
}
The jquery is as follow
$(document).mousemove(function(event) {
$('#light').offset({
top: event.pageY - 50,
left: event.pageX - 50
});
});
And last the HTML
<div id="image"></div>
<div id="overlay"></div>
<div id="light"></div>
instead an overlay, you could use a box-shadow:
$(document).mousemove(function(event) {
$('#light').offset({
top: event.pageY - 50,
left: event.pageX - 50
});
});
* {
margin: 0;
padding: 0;
}
#image {
background: url(https://placeimg.com/640/480/animals) center no-repeat;
width: 800px;
height: 600px;
}
#light {
opacity: 1;
top: 50%;
left: 50%;
width: 100px;
height: 100px;
border-radius: 50%;
position: absolute;box-shadow:0 0 0 3000px rgba(0,0,0,0.9);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="image"></div>
<div id="light"></div>
You can create a fake image and calculate the offset of the background image like this:
CSS
* {
margin: 0;
padding: 0;
}
.image {
background: url(https://placeimg.com/640/480/animals) center no-repeat;
}
#image {
width: 800px;
height: 600px;
top:0px;
left:0px;
}
#overlay {
opacity: 0.9;
background: #000;
width: 100%;
height: 100%;
top: 0;
left: 0;
position: fixed;
}
#fakeImage {
position:absolute;
width: 800px;
height: 600px;
}
#light {
opacity: 1;
top: 50%;
left: 50%;
width: 100px;
height: 100px;
border-radius: 50%;
position: relative;
background: #fff;
overflow:hidden;
}
HTML
<div id="image" class="image"></div>
<div id="overlay"></div>
<div id="light" style="display:none;">
<div id="fakeImage" class="image"></div>
</div>
JS
$(document).mousemove(function(event) {
$('#light').offset({
top: event.pageY - 50,
left: event.pageX - 50
});
var _top = (- $('#light').offset().top) + 'px';
var _left = (- $('#light').offset().left) + 'px';
$('#fakeImage').css({'top': _top, 'left': _left });
});
The random image required a unique class with the same image.
JSFiddle example
Add a massive border to the #light and add a negative margin:
https://jsfiddle.net/mpcmvej6/
.
And remove #overlay.
This method seems the most simple to me.
The good part about this method is that there is no need to support box shadow and it does not require a second image element.
Another method is putting a copy of the image inside #light and move it in the opposite direction of #light.

CSS Scaled Div Centring

I am having an issue centring a <div id='divTwo'> inside another <div id='divOne'>. This is normal an easy thing to do, however in this instance i have transform: scale(); with transform-origin: 50% 50% 0px; applied on 'divTwo'
#divOne {
top: 0px;
left: 0px;
width: 100%;
height: 100%;
}
#divTwo {
width: 1024px;
height: 768px;
margin: auto;
position: absolute;
top: 0; left: 0; bottom: 0; right: 0;
border-left: 131px solid #333333;
border-right: 131px solid #333333;
border-top: 47.5px solid #333333;
border-bottom: 47.5px solid #333333;
border-radius: 55px;
}
if the scale applied to the transform and the window is larger than the outerWidth(), 'divTwo' has no issue centring. However when the 'divTwo' is scaled and the window is smaller or equal to the outerWidth(). The div will no longer centre, instead it will place its centre point to be right side of the browser, resulting if half the of 'divTwo' being off the right hand-side of the browser. Changing transform-origin: 50% 50% 0px; to transform-origin: 0% 50% 0px; works so long as you don't scale vertically, and vice versa.
jsfiddle example : https://jsfiddle.net/yvyz49zp/
Thank you. I feel like am missing something of obvious.
I knocked this up relatively quickly in jsfiddle - no javascript needed. Just play around with the values until you get something you like.
Code:
body {
background: lightblue;
}
#container {
display: inline-block;
position: absolute;
width: 50%;
right: 50%;
top: 50%;
transform: translate(50%, -50%);
}
#dummy {
margin-top: 75%; /* Using the dummy is the trick - it locks the aspect ratio (at 4:3 in this case) */
}
#device {
position: absolute;
top: 10%;
bottom: 10%;
left: 0;
right: 0;
background-color: #333;
border-radius: 10%;
}
#screen {
position: absolute;
width: 70%;
height: 80%;
background: #0f0;
right: 50%;
top: 50%;
transform: translate(50%, -50%);
}
<div id="container">
<div id="dummy"></div>
<div id="device">
<div id="screen"></div>
</div>
</div>

Keep element in original position after scaling from center

So i want to know how to calculate translate css property value for element that is scaled from center (css: transform-origin: 50% 50% 0).
Here is my HTML and CSS (FIDDLE: http://jsfiddle.net/rPNyM/)
HTML:
<div id="holder">
<div id="dot"></div>
<div id="box"></div>
</div>
CSS:
#holder {
position: absolute;
width: 500px;
height: 500px;
background: #226699;
}
#dot {
position: absolute;
left: 100px;
top: 100px;
width: 5px;
height: 5px;
background: #ff0000;
z-index: 20;
}
#box {
position: absolute;
left: 100px;
top: 100px;
width: 100px;
height: 100px;
background: #000;
transform: translate(-25px, -25px) scale(0.2,0.2);
transform-origin: 50% 50% 0;
-moz-transform: translate(-25px, -25px) scale(0.2,0.2);
-moz-transform-origin: 50% 50% 0;
}
The black box should be in same (left top) position as red box even when scale value is changed.
Found the answer by my self (tested some calculations).
Just calculate like this (Javascript):
var pad_x = ((elem_width * scale) - elem_width) / 2;
var pad_y = ((elem_height * scale) - elem_height) / 2;

Categories