Rotate drop-shadow effect with CSS - javascript

The question is almost the same as this: how to rotate the shadow effect with CSS?
But my question is a bit more complicated: i use "filter: drop-shadow" because object that i want to have shadow effect is composite - it consists of two primitive figures.
I achieved the desired effect with JS - just rotating the main object and then calculating drop-shadow direction. But the shadow blinks on rerendering, it is visible at least in Chrome.
(function() {
const RAD_TO_DEG = 180/Math.PI,
DEG_TO_RAD = Math.PI/180;
var arrow = document.getElementsByClassName('arrow')[0],
arrow_shadow_color = 'rgba(50,50,50,0.25)',
previous_x = 0,
previous_y = 0,
shadow_angle = -45,
shadow_blur_radius = 5,
shadow_offset = 15,
shadow_string_right = 'px ' + shadow_blur_radius + 'px ' + arrow_shadow_color + ')',
amount_of_attempts_to_skip = 10,
n = 0;
dropShadow(180);
document.addEventListener('mousemove', mouseMove);
function mouseMove(e) {
n++;
if (n%amount_of_attempts_to_skip === 0) {
var angle = Math.atan2( previous_y - e.pageY, e.pageX - previous_x ) * RAD_TO_DEG;
arrow.style.transform = 'rotate(' + (180 - ~~angle) + 'deg)';
dropShadow(angle);
previous_x = e.pageX;
previous_y = e.pageY;
}
}
function dropShadow(angle) {
angle = 180 - shadow_angle + angle;
var x = ( shadow_offset * Math.cos( angle * DEG_TO_RAD) ).toFixed(2),
y = ( shadow_offset * Math.sin( angle * DEG_TO_RAD) ).toFixed(2);
arrow.style.filter = 'drop-shadow(' + x + 'px ' + y + shadow_string_right;
}
})();
html, body {
width: 100%;
height: 100%;
box-sizing: border-box;
}
* {
margin: 0;
border: 0;
padding: 0;
position: relative;
box-sizing: inherit;
}
.container {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-100%, -50%);
}
.arrow {
width: 75px;
height: 20px;
background: #2ECC40;
transform-origin: right;
transition: all 0.15s ease;
}
.arrow:before {
content: "";
position: absolute;
border-bottom: 15px solid transparent;
border-right: 20px solid #2ECC40;
border-top: 15px solid transparent;
height: 0px;
width: 0px;
margin-left: -20px;
margin-top: -5px;
}
<div class="container"><div class="arrow"></div></div>
So the question is: is it possible to create a shadow effect for a composite object with CSS and then rotate it so that it keeps the absolute angle with CSS?
Or maybe at least with JS but some other way but manually setting x and y filter offsets.
UPD: i just realized that there is just no need to dynamically apply drop-shadow style - it can be applied to a container: there will be no rerendering flashes, no need to apply some techniques to smoothen the shadow movement, no need to manually calculate shadow offset, that's it. I answered my own question 'cuz it was silly.

I just realized that there is just no need to dynamically apply drop-shadow style - it can be applied to a container: there will be no rerendering flashes, no need to apply some techniques to smoothen the shadow movement, no need to manually calculate shadow offset, that's it. All of these will be rendered automatically.
So the answer for "is it possible to create a shadow effect for a composite object with CSS and then rotate it so that it keeps the absolute angle with CSS?" is Yes, it is possible: just apply drop-shadow filter to the container of the element that you want to have a shadow effect.
Stackoverflow, sorry for asking silly questions.

Shadow blinking is out of bug. I fixed your thing at my CodePen and below. Your project's arrow will get dynamic shadow with only CSS if you create pseudo element which will move with cursor.
That flickering of the shadow of 3D objects upon cursor move is browser specific long known CSS related kind of bug with fixes available everywhere. You only needed to know that matter. You can search StackOverflow and perform web search now. Two ways has minor difference in CSS. But both actually works. I have not changed your javascript.
You can read/see W3C docs, CSS tricks's this, CSS trick's this,W3 School and this code pen for CSS pseudo element drag-able drop shadow.
For your case I modified this :
.arrow {
width: 75px;
height: 20px;
background: #2ECC40;
transform-origin: right;
transition: all 0.01s ease;
transform-style: preserve-3d;
-webkit-transform: rotateY(60deg);
-webkit-transform-style: preserve-3d;
transform: rotateY(60deg);
(function() {
const RAD_TO_DEG = 180/Math.PI,
DEG_TO_RAD = Math.PI/180;
var arrow = document.getElementsByClassName('arrow')[0],
arrow_shadow_color = 'rgba(50,50,50,0.25)',
previous_x = 0,
previous_y = 0,
shadow_angle = -45,
shadow_blur_radius = 5,
shadow_offset = 15,
shadow_string_right = 'px ' + shadow_blur_radius + 'px ' + arrow_shadow_color + ')',
amount_of_attempts_to_skip = 10,
n = 0;
dropShadow(180);
document.addEventListener('mousemove', mouseMove);
function mouseMove(e) {
n++;
if (n%amount_of_attempts_to_skip === 0) {
var angle = Math.atan2( previous_y - e.pageY, e.pageX - previous_x ) * RAD_TO_DEG;
arrow.style.transform = 'rotate(' + (180 - ~~angle) + 'deg)';
dropShadow(angle);
previous_x = e.pageX;
previous_y = e.pageY;
}
}
function dropShadow(angle) {
angle = 180 - shadow_angle + angle;
var x = ( shadow_offset * Math.cos( angle * DEG_TO_RAD) ).toFixed(2),
y = ( shadow_offset * Math.sin( angle * DEG_TO_RAD) ).toFixed(2);
arrow.style.filter = 'drop-shadow(' + x + 'px ' + y + shadow_string_right;
}
})();
html, body {
width: 100%;
height: 100%;
box-sizing: border-box;
transform-style: preserve-3d;
-webkit-transform-style: preserve-3d;
}
* {
margin: 0;
border: 0;
padding: 0;
position: relative;
box-sizing: inherit;
transform-style: preserve-3d;
}
.container {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-100%, -50%);
transform-style: preserve-3d;
-webkit-transform-style: preserve-3d;
}
.arrow {
width: 75px;
height: 20px;
background: #2ECC40;
transform-origin: right;
transition: all 0.01s ease;
transform-style: preserve-3d;
-webkit-transform: rotateY(60deg);
-webkit-transform-style: preserve-3d;
transform: rotateY(60deg);
}
.arrow:before {
content: "";
position: absolute;
border-bottom: 15px solid transparent;
border-right: 20px solid #2ECC40;
border-top: 15px solid transparent;
height: 0px;
width: 0px;
margin-left: -20px;
margin-top: -5px;
}
<div class="container"><div class="arrow"></div></div>

Depends on what kind of solution you are looking for. If you need a lot of elements with shadows, it's better to use a prerendered image. Browser won't spend time calculating all the shadows and rotations for each element.
If you absolutely need a shadow on a composite object with CSS, use box-shadow. There is a hacky way to make a triangle with the shadow. It's much better and efficient to use an image though!
Here by rotating the wrapper element we rotate all of its children and automatically their box-shadow:
(matrix value is taken from the computed style)
<!doctype html>
<html>
<head>
<style>
#keyframes rotate {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
.arrow {
top: 150px;
left: 50px;
position: relative;
display: block;
width: 280px;
animation: rotate 5s infinite linear;
}
.arrow div {
display: inline-block;
position: absolute;
}
.arrow-body {
width: 251px;
height: 25px;
top: 16px;
background: green;
box-shadow: 1px 5px 0 0 black;
}
.arrow-head {
width: 0;
height: 0;
right: 0;
bottom: -84px;
box-sizing: border-box;
border: 1em solid black;
border-color: transparent transparent green green;
transform-origin: 0 0;
transform: rotate(225deg);
box-shadow: -5px 1px 0 0 black;
}
#log {
font-family: monospace;
}
</style>
<script>
setInterval(function(){
var a = document.getElementById("arrow");
var l = document.getElementById("log");
l.innerHTML = ".arrow { transform: " + window.getComputedStyle(a, null).getPropertyValue("transform") + " }";
}, 10);
</script>
</head>
<body>
<span id="log"></span>
<div class="arrow" id="arrow">
<div class="arrow-body"></div>
<div class="arrow-head"></div>
</div>
</body>
</html>

Related

Transition is not working properly in Safari

So I've made a custom cursor for my next website. In Chrome it works as it should but in Safari it's laggy...
I've tried several things like using the webkit stuff but it still doesn't work.
here is the Codepen
html
<div class="cursor"></div>
css
body{
background: #fff;
width: 100%;
height: 100vh;
}
.cursor{
position: fixed;
left: 0px;
top: 0;
width: 25px;
height: 25px;
transition-duration:0.3s;
-webkit-transition-duration:0.3s;
-ms-transition-duration:0.3s;
-moz-transition-duration:0.3s;
transition-timing-function: cubic-bezier(.33,.81,.66,.95);
-webkit-transition-timing-function: cubic-bezier(.33,.81,.66,.95);
-moz-transition-timing-function: cubic-bezier(.33,.81,.66,.95);
background-color: #fff;
mix-blend-mode: difference;
border-radius: 50%;
pointer-events: none;
}
js
let cursor = document.querySelector('.cursor');
document.addEventListener('mousemove', moveCursor);
function moveCursor(e) {
let x = e.clientX;
let y = e.clientY;
cursor.style.transform = `translate(calc(${x}px - 50%), calc(${y}px - 50%))`
}
I've had nothing but trouble with dynamic transform values in safari. It seems they calculate positions in the window space a little different than other browsers. No source on that one, just my own trials and tribulations.
I would suggest you change your approach, and use top and left values.
I tested this in safari and it's miles more responsive.
let cursor = document.querySelector('.cursor');
document.addEventListener('mousemove', moveCursor);
function moveCursor(e) {
let x = e.clientX;
let y = e.clientY;
cursor.style.top = `${y}px`
cursor.style.left = `${x}px`
}
body {
background: #fff;
width: 100%;
height: 100vh;
}
.cursor {
position: fixed;
left: 0px;
top: 0;
width: 25px;
height: 25px;
transition-duration: 0.3s;
transition-timing-function: cubic-bezier(.33, .81, .66, .95);
background-color: #fff;
mix-blend-mode: difference;
border-radius: 50%;
pointer-events: none;
transform: translate(-50%, -50%);
}
<div class="cursor"></div>
I kept the translate(-50%, -50%) as a permanent value on the cursor, and only updated top and left with javascript.
As a side note, the vendor prefixes are not really necessary for those properties. No need to add them. https://caniuse.com/css-transitions
The translate calc in you js is forcing the cursor to the center.
The transition delay is too long preventing it for following the cursor.
Codepen: https://codepen.io/diomedefan/pen/RwMaYWe
let cursor = document.querySelector('.cursor');
document.addEventListener('mousemove', moveCursor);
function moveCursor(e) {
let x = e.clientX;
let y = e.clientY;
cursor.style.transform = `translate(calc(${x}px), calc(${y}px))`
}
body{
background: #fff;
width: 100%;
height: 100vh;
}
.cursor{
position: fixed;
left: 0px;
top: 0;
width: 25px;
height: 25px;
transition-duration:0.2s;
-webkit-transition-duration:0.2s;
-ms-transition-duration:0.2s;
-moz-transition-duration:0.2s;
transition-timing-function: cubic-bezier(.33,.81,.66,.95);
-webkit-transition-timing-function: cubic-bezier(.33,.81,.66,.95);
-moz-transition-timing-function: cubic-bezier(.33,.81,.66,.95);
background-color: #fff;
mix-blend-mode: difference;
border-radius: 50%;
pointer-events: none;
}
<div class="cursor"></div>
The answer for my particular case was pretty interesting.
Instead of using css transitions I used a lerp function in javascript:
var mouseX = window.innerWidth / 2,
mouseY = window.innerHeight / 2;
var $ = jQuery
var circle = {
el: $('.cursor'),
x: window.innerWidth / 2,
y: window.innerHeight / 2,
w: 25,
h: 25,
update: function() {
l = this.x - this.w / 2;
t = this.y - this.h / 2;
this.el.css({
'transform': 'translate3d(' + l + 'px, ' + t + 'px, 0)'
});
}
}
$(window).mousemove(function(e) {
mouseX = e.clientX;
mouseY = e.clientY;
})
setInterval(move, 1000 / 60)
function move() {
circle.x = lerp(circle.x, mouseX, 0.1);
circle.y = lerp(circle.y, mouseY, 0.1);
circle.update()
}
function lerp(start, end, amt) {
return (1 - amt) * start + amt * end
}
.cursor {
position: absolute;
width: 25px;
height: 25px;
transition: height 0.3s ease-in-out, width 0.3s ease-in-out;
top: 0;
left: 0;
z-index: 999;
background-color: #fff;
mix-blend-mode: difference;
border-radius: 50%;
pointer-events: none;
}
body {
background: #fff;
}
<div class="cursor"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
r

How to conform top glare to all child elements

Goal
Make the glare layer on all visible children like a clip-path
––––––––––––
Heads Up
Child elements can be any shape with any animation
Child elements can be any svg shape with any kind of animation attached to it
So glare must be automatically dynamic and conforming
––––––––––––
What I've Done
I create an apple TV effect…
But the glare only works as a box on top of other boxes.
The glare does not conform to other shapes
Example Below
––––––––––––
What I Can't Use
Canvas - No Canvas Please - I'm not familiar with it
Clip-Path - Because child elements can be anything overflowing outside of the glare
––––––––––––
What I'm looking for
Some kind of magical CSS line of code that makes the glare layer conform to all elements under it… like a normal glare would work.
Is this possible?
Is there some way Javascript can glare it automatically?
Is there some kind of mix-blend-mode I can use to make the glare just work?
Or is this something that is just impossible?
Glare should not look like a box
––––––––––––
What I tried
I tried to scale the glare layer to scale(1.1) and use some mix-blend-mode
But I couldn't figure out how to make it work.
appleTV();
function appleTV(){
appleTVComponents = 0;
function rotateX(n) {return ' rotateX('+n+'deg)'}
function rotateY(n) {return ' rotateY('+n+'deg)'}
function translateX(n) {return ' translateX('+n+'px)'}
function translateY(n) {return ' translateY('+n+'px)'}
function perspective(n) {return 'perspective('+n+'px)'}
function scale(n) {return ' scale3d('+n+','+n+','+n+')'}
function section(s='',e) {e=document.createElement('section');e.className='appletv_'+s;return e;}
function getWidth(e) {return e.clientWidth || e.offsetWidth || e.scrollWidth}
function setPerspective(e) {e.style.transform = perspective(getWidth(e)*3);}
function preventScroll(state) {if(supportsTouch){win.preventScroll=state||false;}}
function preventDefault(e) {if (supportsTouch&&win.preventScroll){e.preventDefault();}}
function isTouchScreen() {return 'ontouchstart' in window || navigator.msMaxTouchPoints}
function child(e) {return e.firstChild;}
function children(e) {return [...e.children]}
let body = document.body,
win = window,
imgs = document.querySelectorAll('.appletv'),
totalImgs = imgs.length,
supportsTouch = isTouchScreen(),
move = 'mousemove',
start = 'mouseenter',
end = 'mouseleave';
if(supportsTouch){move='touchmove'; start='touchstart'; end='touchend';}
if(totalImgs <= 0){return;}
for(var l=0;l<totalImgs;l++){
var thisImg = imgs[l],
layerElems = [...thisImg.querySelectorAll('.appletv_layer')];
if(!layerElems.length){continue;}
while(thisImg.firstChild) {thisImg.removeChild(thisImg.firstChild);}
var containerHTML = section(''),
shineHTML = section('gloss'),
shadowHTML = section('shadow'),
layersHTML = section('layer'),
layers = [];
thisImg.id = 'appletv_'+(++appleTVComponents);
layerElems.forEach((e,i)=>{
let layer_ = section('rendered_layer')
layer = section(''),
img = e.getAttribute('data-img');
layer_.setAttribute('data-layer',i);
[...e.children].forEach(c=>{layer.appendChild(c)})
if (img) {layer.style.backgroundImage = 'url('+img+')';}
layer_.appendChild(layer);
layersHTML.appendChild(layer_);
layers.push(layer);
});
[shadowHTML,layersHTML,shineHTML].forEach(e=>{containerHTML.appendChild(e)});
thisImg.appendChild(containerHTML);
var w = getWidth(thisImg);
setPerspective(thisImg)
preventScroll();
(function enableMovements(_thisImg,_layers,_totalLayers,_shine) {
thisImg.addEventListener(move, e=>{processMovement(e,supportsTouch,_thisImg,_layers,_totalLayers,_shine);});
thisImg.addEventListener(start, e=>{processEnter(_thisImg);});
thisImg.addEventListener(end, e=>{processExit(_thisImg,_layers,_totalLayers,_shine);});
})(thisImg,layers,layerElems.length,shineHTML);
};
function processMovement(e, touchEnabled, elem, layers, totalLayers, shine){
preventDefault(e)
let bdst = body.scrollTop,
bdsl = body.scrollLeft,
pageX = (touchEnabled)? e.touches[0].pageX : e.pageX,
pageY = (touchEnabled)? e.touches[0].pageY : e.pageY,
offsets = elem.getBoundingClientRect(),
w = elem.clientWidth || elem.offsetWidth || elem.scrollWidth, // width
h = elem.clientHeight || elem.offsetHeight || elem.scrollHeight, // height
wMultiple = 320/w,
offsetX = 0.52 - (pageX - offsets.left - bdsl)/w, //cursor position X
offsetY = 0.52 - (pageY - offsets.top - bdst)/h, //cursor position Y
dy = (pageY - offsets.top - bdst) - h / 2, //#h/2 = center of container
dx = (pageX - offsets.left - bdsl) - w / 2, //#w/2 = center of container
yRotate = (offsetX - dx)*(0.07 * wMultiple), //rotation for container Y
xRotate = (dy - offsetY)*(0.1 * wMultiple), //rotation for container X
imgCSS = rotateX(xRotate)+rotateY(yRotate), //img transform
arad = Math.atan2(dy, dx), //angle between cursor and center of container in RAD
angle = arad * 180 / Math.PI - 90; //convert rad in degrees
if (angle < 0) {angle = angle + 360;}
if(elem.firstChild.className.indexOf(' over') != -1){imgCSS += scale(1.07);}
elem.firstChild.style.transform = imgCSS;
shine.style.background = 'linear-gradient(' + angle + 'deg, rgba(255,255,255,' + (pageY - offsets.top - bdst)/h * 0.4 + ') 0%,rgba(255,255,255,0) 80%)';
shine.style.transform = translateX((offsetX * totalLayers) - 0.1)+translateY((offsetY * totalLayers) - 0.1);
var revNum = totalLayers;
for(var ly=0;ly<totalLayers;ly++){
layers[ly].style.transform = translateX((offsetX * revNum) * ((ly * 2.5) / wMultiple))+translateX((offsetY * totalLayers) * ((ly * 2.5) / wMultiple));
revNum--;
}
}
function processEnter(e){preventScroll(true);setPerspective(e);child(e)&&child(e).classList.add('over');}
function processExit(elem, layers, totalLayers, shine){preventScroll();
child(elem).classList.remove('over')
child(elem).style.transform = '';
shine.style = '';
layers.forEach(e=>{e.style.transform = ''})
}
}
body,
html {
height: 100%;
min-height: 100%;
}
body {background: linear-gradient(to bottom, #f6f7fc 0%, #d5e1e8 40%);}
.center{
position: absolute;
left: 50%;
margin: 10px auto;
transform: translateX(-50%);
}
.appletv {
position: relative !important;
margin: 0 auto !important;
display: inline-block;
width: 300px;
height: 150px;
border-radius: 5px;
transform-style: preserve-3d;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
cursor: pointer;
backface-visibility: hidden;
}
.appletv.depressed {
margin-top: 25px;
box-shadow: 0 5px 30px rgba(0, 0, 0, 0.4);
}
.appletv_ {
position: relative;
width: 100%;
height: 100%;
border-radius: 5px;
transition: all 0.2s ease-out;
background: teal;
}
.appletv_container.over {z-index: 1;}
.appletv_container.over .appletv_shadow {box-shadow: 0 45px 100px rgba(14, 21, 47, 0.4), 0 16px 40px rgba(14, 21, 47, 0.4);}
.appletv_layer {
position: relative;
width: 100%;
height: 100%;
border-radius: 5px;
/*overflow: hidden;*/
transform-style: preserve-3d;
}
.appletv_rendered_layer {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
overflow: hidden;
border-radius: 5px;
transition: all 0.1s ease-out;
transform-style: preserve-3d;
}
.appletv_rendered_layer > :first-child {
position: absolute;
width: 104%;
height: 104%;
top: -2%;
left: -2%;
background-repeat: no-repeat;
background-position: center;
background-color: transparent;
background-size: cover;
transition: all 0.1s ease-out;
}
.appletv_shadow {
position: absolute;
top: 5%;
left: 5%;
width: 90%;
height: 90%;
transition: all 0.2s ease-out;
box-shadow: 0 8px 30px rgba(14, 21, 47, 0.6);
}
.appletv_gloss {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
border-radius: 5px;
/*display: none !important;*/
background: linear-gradient(135deg, rgba(255, 255, 255, 0.25) 0%, rgba(255, 255, 255, 0) 40%);
}
[data-layer="1"] {overflow: visible !important;}
[data-layer="1"] > section > section {
position: absolute;
background: rgb(50, 141, 210);
width: 60px;
height: 60px;
border-radius: 10px;
}
[data-layer="1"] > section > section:first-child {
left: -30px;
top: -10px;
}
[data-layer="1"] > section > section:last-child {
right: -20px;
top: 50px;
}
#keyframes rotate {
0% {transform: rotate(0);}
100% {transform: rotate(359deg);}
}
.appletv_gloss {
/*display: none;*/
background-blend-mode: multiply;
}
.appletv [data-layer="1"] {
transform: scale(0.5);
transition: .3s ease-in-out 0s;
}
.appletv:hover [data-layer="1"] {
transform: scale(1);
}
.appletv:hover [data-layer="1"] > section > section {
animation: rotate 10s linear 0s infinite;
}
.appletv:hover [data-layer="1"] > section > section:last-child {
animation: rotate 25s linear 0s infinite;
}
#hover {
font-size: 30px;
position: absolute;
top: 37%;
text-align: center;
width: 100%;
color: white;
text-shadow: 0 2px 2px rgba(0,0,0,0.3) ;
}
<html>
<body>
<section class="center">
<section class="appletv">
<section class="appletv appletv_layer" data-img="https://source.unsplash.com/random">
<section id="hover">Hover Corners</section>
</section>
<section class="appletv appletv_layer">
<section></section>
<section></section>
</section>
</section>
</section>
</body>
</html>

Perfectly positioned tooltips with position: fixed

I'm trying to create some very basic tooltips but I'm having trouble calculating the exact position these should go in with some JavaScript. The reason for wanting a fixed position is to make sure these work whenever there is overflow hidden and such.
This is my code so far:
var overflowTooltip = function (elem) {
let legendRow = elem.currentTarget.getBoundingClientRect();
let tooltip = elem.currentTarget.children[2];
let topPosition;
let leftPosition;
if ((elem.currentTarget.offsetWidth < elem.currentTarget.scrollWidth) && tooltip !== undefined) {
tooltip.classList.add('total-opacity');
$timeout(function () {
if (tooltip.offsetHeight > 35) {
topPosition = (legendRow.top - tooltip.offsetHeight / 4) - 65;
} else {
topPosition = legendRow.top - 65;
}
leftPosition = (legendRow.left + elem.currentTarget.offsetWidth) / 2;
tooltip.style.left = leftPosition + 'px';
tooltip.style.top = topPosition + 'px';
$timeout(function () {
tooltip.classList.remove('total-opacity');
}, 400)
}, 100);
} else {
elem.currentTarget.children[2].style.left = '-9999px';
}
}
And some SASS:
.custom-tooltip {
font-family: $brand-font-condensed;
font-size: 14px;
font-weight: 400;
position: fixed;
text-align: left;
overflow: visible !important;
background-color: rgba($dark-gray, 0.95);
color: #fff;
height: auto;
padding: 7px 10px;
z-index: 9000;
visibility: hidden;
opacity: 0;
border-radius: 2px;
box-shadow: 0 2px 5px 0 rgba(#000, 0.16), 0 2px 10px 0 rgba(#000, 0.12);
#include transition (.2s ease-in);
left: -9999px;
&:hover {
visibility: visible;
opacity: 1;
#include transition (.2s ease-out);
-webkit-transition-delay: .3s;
transition-delay: .3s;
}
}
The above works but it's not perfect. if I wanna change around the position for it to appear on the left, right, bottom. I'd have to so some refactoring. If the tooltip's height is bigger or smaller, the position changes, If I scroll up or down, the tooltip stays stuck on screen for a few seconds. etc. Lots of these little details which are pretty annoying.
Not interested in using a plugin at the moment nor jQuery. Thanks for any suggestion or feedback :)

How to create image zoom effect using jquery?

I'm trying to create an image zoom effect similar to this one. I've managed to search a plugin called prefixfree.js and tried it in my code, but it did not work, its just showing the image but when I hover it there is no image zoom effect.
The link for the plugin is this. It should suppose to work like this.
Also for additional info, the size for the large image is 1406X1275 and the small image is 200X200. Kindly help me on solving this one or provide better alternatives.
$(document).ready(function() {
var native_width$ = 0;
var native_height = 0;
$(".magnify").mousemove(function(e) {
//When the user hovers on the image, the script will first calculate
//the native dimensions if they don't exist. Only after the native dimensions
//are available, the script will show the zoomed version.
if (!native_width && !native_height) {
//This will create a new image object with the same image as that in .small
//We cannot directly get the dimensions from .small because of the
//width specified to 200px in the html. To get the actual dimensions we have
//created this image object.
var image_object = new Image();
image_object.src = $(".small").attr("src");
//This code is wrapped in the .load function which is important.
//width and height of the object would return 0 if accessed before
//the image gets loaded.
native_width = image_object.width;
native_height = image_object.height;
} else {
//x/y coordinates of the mouse
//This is the position of .magnify with respect to the document.
var magnify_offset = $(this).offset();
//We will deduct the positions of .magnify from the mouse positions with
//respect to the document to get the mouse positions with respect to the
//container(.magnify)
var mx = e.pageX - magnify_offset.left;
var my = e.pageY - magnify_offset.top;
//Finally the code to fade out the glass if the mouse is outside the container
if (mx < $(this).width() && my < $(this).height( && mx > 0 && my > 0) {
$(".large").fadeIn(100);
} else {
$(".large").fadeOut(100);
}
if ($(".large").is(":visible")) {
//The background position of .large will be changed according to the position
//of the mouse over the .small image. So we will get the ratio of the pixel
//under the mouse pointer with respect to the image and use that to position the
//large image inside the magnifying glass
var rx = Math.round(mx / $(".small").width() * native_width - $(".large").width() / 2) * -1;
var ry = Math.round(my / $(".small").height() * native_height - $(".large").height() / 2) * -1;
var bgp = rx + "px " + ry + "px";
//Time to move the magnifying glass with the mouse
var px = mx - $(".large").width() / 2;
var py = my - $(".large").height() / 2;
//Now the glass moves with the mouse
//The logic is to deduct half of the glass's width and height from the
//mouse coordinates to place it with its center at the mouse coordinates
//If you hover on the image now, you should see the magnifying glass in action
$(".large").css({
left: px,
top: py,
backgroundPosition: bgp
});
}
}
})
})
* {
margin: 0;
padding: 0;
}
.magnify {
width: 200px;
margin: 50px auto;
position: relative;
}
.large {
width: 175px;
height: 175px;
position: absolute;
border-radius: 100%;
/*Multiple box shadows to achieve the glass effect*/
box-shadow: 0 0 0 7px rgba(255, 255, 255, 0.85), 0 0 7px 7px rgba(0, 0, 0, 0.25), inset 0 0 40px 2px rgba(0, 0, 0, 0.25);
/*Lets load up the large image first*/
background: url('microsoftLogo1.jpg') no-repeat;
/*hide the glass by default*/
display: none;
}
#subPic1 {
border: 1px solid black;
margin: 5px;
width: 50px;
height: 50px;
}
#subPic2 {
border: 1px solid black;
margin: 5px;
width: 50px;
height: 50px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<div class="magnify">
<div class="large"></div>
<img class="small" src="microsoftLogo1Small.jpg" />
</div>
<script src="http://thecodeplayer.com/uploads/js/prefixfree.js" type="text/javascript"></script>
<img id="subPic1" src="microsoftLogo1.jpg" onclick="getImage1()" /><br/>
<img id="subPic2" src="microsoftLogo2.jpg" onclick="getImage2()" />
HTML
<img src="sample.png" class="zoom" />
CSS
img.zoom {
width: 350px;
height: 200px;
-webkit-transition: all .2s ease-in-out;
-moz-transition: all .2s ease-in-out;
-o-transition: all .2s ease-in-out;
-ms-transition: all .2s ease-in-out;
}
.transition {
-webkit-transform: scale(1.8);
-moz-transform: scale(1.8);
-o-transform: scale(1.8);
transform: scale(1.8);
}
JavaScript
$(document).ready(function(){
$('.zoom').hover(function() {
$(this).addClass('transition');
}, function() {
$(this).removeClass('transition');
});
});
HTML
<div class="item">
<img src="pepsi.jpg" alt="pepsi" width="540" height="548">
<div class="item-overlay top"></div>
</div>
CSS
* {
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
margin: 0;
padding: 0;
}
.item {
position: relative;
border: 1px solid #333;
margin: 2%;
overflow: hidden;
width: 540px;
}
.item img {
max-width: 100%;
-moz-transition: all 0.3s;
-webkit-transition: all 0.3s;
transition: all 0.3s;
}
.item:hover img {
-moz-transform: scale(1.1);
-webkit-transform: scale(1.1);
transform: scale(1.1);
}

Why is my 3d cube not rotating as expected?

I'm doing a 3d dice that rotates when you swipe its face. The problem is that it is acting really weird on some cases. For example, if you run the snippet and swipe left two times then swipe down, it does a crazy rotation...
Here is the code:
$(function() {
var X = 0,
Y = 0;
var hammertime = new Hammer($(".thirdDimension")[0], {domEvents: true});
hammertime.get('swipe').set({ direction: Hammer.DIRECTION_ALL });
function rotate(what) {
switch (what) {
case "X":
$(".cube").css("transform", "rotateX(" + X + "deg) rotateY(" + Y +"deg)");
break;
case "Y":
$(".cube").css("transform", "rotateY(" + Y +"deg) rotateX(" + X + "deg)");
break;
}
$("#debug").html($("#debug").html() + $(".cube").attr("style") + "<br>").scrollTop($("#debug")[0].scrollHeight);
}
$(".thirdDimension").on("swipeleft", function(e){
Y -= 90;
rotate("Y");
});
$(".thirdDimension").on("swiperight", function(e){
Y += 90;
rotate("Y");
});
$(".thirdDimension").on("swipeup", function(e){
X += 90;
rotate("X");
});
$(".thirdDimension").on("swipedown", function(e){
X -= 90;
rotate("X");
});
});
* {
box-sizing: border-box;
}
html, body {
height: 100%;
font-family: sans-serif;
}
.tableContainer, .vcenter {
height: 100%;
width: 100%;
}
.tableContainer {
display: table;
}
.vcenter {
height: 100%;
display: table-cell;
vertical-align: middle;
}
.thirdDimension {
perspective: 500px;
perspective-origin: 50% 100px;
}
.cube {
margin: 0 auto;
position: relative;
width: 200px;
height: 200px;
transform-style: preserve-3d;
}
.cube div {
position: absolute;
width: 200px;
height: 200px;
box-shadow: inset 0 0 30px black;
font-size: 72pt;
padding-top: 35px;
text-align: center;
background-color: black;
}
.right {
transform: rotateY(-270deg) translateX(100px);
transform-origin: top right;
}
.left {
transform: rotateY(270deg) translateX(-100px);
transform-origin: center left;
}
.up {
transform: rotateX(90deg) translateY(-100px);
transform-origin: top center;
}
.down {
transform: rotateX(-90deg) translateY(100px);
transform-origin: bottom center;
}
.front {
transform: translateZ(100px);
}
.back {
transform: translateZ(-100px) rotateY(180deg);
}
.cube {
-webkit-transition: .3s all linear;
cursor: pointer;
}
.cube div:after {
display: block;
position: absolute;
width: 100px;
height: 100px;
content: "";
border: 1px solid;
}
.front:after {
top: 0;
right: 0;
background-color: green;
}
.back:after {
bottom: 0;
right: 0;
background-color: blue;
}
.right:after {
top: 0;
left: 0;
background-color: red;
}
.left:after {
bottom: 0;
left: 0;
background-color: DarkOrange;
}
.up:after {
right: 0;
bottom: 0;
background-color: white;
}
.down:after {
bottom: 0;
left: 0;
background-color: yellow;
}
#debug {
position: fixed;
background-color: cyan;
overflow: auto;
height: 50px;
width: 100%;
}
/*
.cube {
animation: linear 5s rotate infinite;
}
#-webkit-keyframes rotate {
0% {
transform: rotateX(0deg) rotateY(0deg);
}
100% {
transform: rotateX(360deg) rotateY(720deg);
}
}
*/
<script src="https://cdnjs.cloudflare.com/ajax/libs/hammer.js/2.0.8/hammer.min.js"></script>
<script src="https://code.jquery.com/jquery-2.2.4.min.js"></script>
<div id='debug'></div>
<div class='tableContainer'>
<div class='vcenter'>
<div class='thirdDimension'>
<div class='cube'>
<div class='up'></div>
<div class='front'></div>
<div class='right'></div>
<div class='left'></div>
<div class='back'></div>
<div class='down'></div>
</div>
</div>
</div>
</div>
EDIT: This link: http://greensock.com/forums/topic/7811-3d-rotation-fixed-axsis/ says that the order of the rotations matter. I changed my code slightly but it keeps rotating unexpectedly...
First: Settings the transform different ways for either "X" or "Y" was causing the massive spinning. I changed them both to:
$(".cube").css("transform", "rotateX(" + X + "deg) rotateY(" + Y +"deg)");
If believe you wish for the cube to always spin in the direction of the swipe. Continue reading if so or if not , all you needed to change was the above code.
Second: When you spin the cube you are changing the orientation. The x-axis is never messed up but the y-axis and z-axis are switching without you really noticing.
Now you can to add rotateZ to the mix:
$(".cube").css("transform", "rotateX(" + X + "deg) rotateY(" + Y +"deg) rotateZ(" + Z + "deg)");
I have changed the code here in this CodePen to provide an example. I have not completed it because I have revealed the issue, but do not have the time to perfect it.
$(function() {
var X = 0,
Y = 0,
Z = 0;
var hammertime = new Hammer($(".thirdDimension")[0], {domEvents: true});
hammertime.get('swipe').set({ direction: Hammer.DIRECTION_ALL });
function rotate() {
$(".cube").css("transform", "rotateX(" + X + "deg) rotateY(" + Y +"deg) rotateZ(" + Z + "deg)");
$("#debug").html($("#debug").html() + $(".cube").attr("style") + "<br>").scrollTop($("#debug")[0].scrollHeight);
}
$(".thirdDimension").on("swipeleft", function(e){
//Y -= 90;
check(-90);
rotate();
});
$(".thirdDimension").on("swiperight", function(e){
//Y += 90;
check(90);
rotate();
});
$(".thirdDimension").on("swipeup", function(e){
X += 90;
rotate();
});
$(".thirdDimension").on("swipedown", function(e){
X -= 90;
rotate();
});
function check(num) {
var temp = Math.abs(X % 360);
switch (temp) {
case 0:
console.log(temp);
Y += num;
break;
case 90:
console.log(temp);
Z -= num
break;
case 180:
console.log(temp);
Y -= num;
break;
case 270:
console.log(temp);
Z -= num;
break;
}
}
});
You need to check the y-axis (Math.abs(Y % 360))) and possibly the z-axis and rotate either the y-axis and z-axis (+- 90) accordingly.
This mostly works, but needs fine tuning in determining the correct axis to rotate. Good luck.
Your problem is more how you have conceptualized rotation than any coding mistakes.
If you rotateY(90), then rotateX(90) - then by the time you get to rotateX(90), your X axis has rotated by 90 degrees, so it is no longer left to right, but into/out of screen. So your thing will look like it's doing a 2d rotate in that particular instance.
And to take it further, if the user now swipes left to right, they are actually swiping along the Z axis, and you need to rotate Z.
To fix this, you need to keep track of the rotation you have done and map the user interface to the cube in a more dynamic way. Swiping left to right doesn't always mean rotate Y, it means rotate along the axis that is currently oriented left to right.
I suggest you find a rubik's cube or similar, and label the sides per axis (e.g. Red side is X axis), simulate the swiping, and then that should make things more clear, as you'll see those axis move around the cube.

Categories

Resources