How to catch atrr transform translatex value? - javascript

I have div, which has some attributes style.
<div class="js__scroll__canvas" style="width: 10054px; transition-timing-function: cubic-bezier(0.1, 0.57, 0.1, 1); transition-duration: 0ms; transform: translate(0px, 0px) translateZ(0px); height: 521px;">
Another plugin js changes transform: translate(0px, 0px) value (bold) - so x position.
I try to catch this value change.
var currentPos = parseInt($(".scroll-container .js__scroll__canvas").attr('style','transform').split(',')[4]);
$(document).on('change', currentPos , function() {
alert( "Handler for .change() called." );
});
But nothing. I try to output currentPos value, but nothing returns, not null, or array, or anything else.
I see unusual structure of style attr transform - transform: translate(0px, 0px) translateZ(0px);. May be problem in that?
Help me please!

I think you want .css not .attr:
var currentPos = parseInt($(".scroll-container .js__scroll__canvas").css('transform').split(',')[4])
The code you have would set the style attribute to "transform":
.attr('style','transform')
Also, this won't work:
$(document).on('change', currentPos , function() {
The second argument to on should be a JQuery selector, not a number. Try this:
var element = $(".scroll-container .js__scroll__canvas");
var currentPos = parseInt(element.css('transform').split(',')[4]);
element.on('change', function() {
var newPos = parseInt(element.css('transform').split(',')[4]);
if(currentPos != newPos) {
currentPos = newPos;
alert("It changed!");
}
});

Related

Element transform scale maintained after transform rotation occurrs

I have an element I am zooming in (one button) and then rotating (another button)
When I zoom in on the element the scale gets updated, then when I go to rotate element the scale is not kept from the zoom (but it really is, I can see the value is maintained browser debug) but it zooms back out to the initial scale when rotate is clicked.
let spin = 0;
let zoom = 1;
$('#SpinRight').click(function(){
//I know for a fact scale keeps value here, but zooms back out to original size when I //click spin
spin += 25;
$('#element').css({'transform' : 'rotate(' + spin + 'deg'});
})
$('#Magnify').click(function(){
zoom += 0.1;
$('#element').css({'transform' : 'scale(' + zoom + ')'});
})
transform rules don't stack, so if you do:
transform: rotate(45deg);
transform: scale(0.5);
The scale transform replaces the rotate rule, it doesn't add to it. If you want both you need to specify them both in a single rule:
transform: rotate(45deg) scale(0.5);
You could keep track of the rotation and scale in css properties and then have a rule that applies them both. (Or just apply them the way you're already doing it, but do both for each update.)
const demo = document.querySelector('.demo');
let rotate = 0;
let scale = 1;
document.querySelector('.rotate').addEventListener('click', () => {
demo.style.setProperty('--rotate', `${rotate += 10}deg`);
});
document.querySelector('.scale').addEventListener('click', () => {
demo.style.setProperty('--scale', scale += 0.1);
});
.demo {
--rotate: 0;
background: skyblue;
width: 100px;
height: 100px;
transform: rotate(var(--rotate, 0)) scale(var(--scale, 1));
}
button {
position: relative; /* just so the buttons stay on top */
}
<div class="demo"></div>
<button class="rotate">Rotate</button>
<button class="scale">Scale</button>

Javascript - set onclick to only first section of page

I am developing this site: https://studioboom.superhi.com/
Is it possible to apply the image click to only the first section, so once scrolled you are able to click on links rather than add an image.
JS:
const images = [
'benjones_flip1.jpg',
'benjones_home1.jpg',
'ben_jones_ts2.jpg',
'benjones_gs1.jpg',
'benjones_jt1.jpg',
'benjones_dlf4.jpg'
]
let i = 0
function placeImage(x, y) {
const nextImage = images[i]
const img = document.createElement('img')
img.classList.add('external-loaded-img')
img.setAttribute('src', nextImage)
img.style.left = x + 'px'
img.style.top = y + 'px'
document.body.appendChild(img)
i = i + 1
if (i >= images.length) {
i = 0
}
}
document.addEventListener('click', function(event) {
event.preventDefault()
placeImage(event.pageX, event.pageY)
})
document.addEventListener('touchend', function(event) {
event.preventDefault()
placeImage(event.pageX, event.pageY)
})
.external-loaded-img {
position: absolute;
transform: translate(-50%, -50%) scale(0.5);
animation: fadein 0.5s;
z-index: 10;
overflow: hidden;
}
#keyframes fadein {
0% {opacity: 0;}
100% {opacity: 1;}
}
Either wait to set up your event handlers until the container of the elements you want them to apply to are present in the page, and then hook up the handlers on that container:
container.addEventListner('click', /*...*/);
container.addEventListner('touchend', /*...*/);
...or keep them hooked up on document, but check when the event occurs that it passed through that container ("event delegation"):
document.addEventListner('click', function(event) {
if (!event.target.closest("selector-for-the-container")) {
return;
}
// ...
});
document.addEventListner('touchend', /*...*/);
if (!event.target.closest("selector-for-the-container")) {
return;
}
// ...
});
More on closest on MDN, including information about polyfills if needed.
document.querySelector(".about").addEventListener('click', function(event) {
event.preventDefault()
placeImage(event.pageX, event.pageY)
})
Something like this does work, if I am clicking on section.photo1, if I clicking on an actual image, it doesn't. Is there a work around for this?
document.addEventListener('click', function(event) {
if (!event.target.closest("section.photo1")) {
return;
}
event.preventDefault()
placeImage(event.pageX, event.pageY)
})

jQuery: Inaccuracy with scrollLeft when scaled

I have a scrollable container with links and thumbnails - scrollLeft to thumbnail depending on the link clicked which works fine, normally.
However, when I scale the main container with transform, scrollLeft scrolls to wrong position.
Any ideas how to resolve this?
scroll: function(){
var chapterName = this.chapter.getAttribute('data-chapter');
var thumbnail = $('.thumbnail-content[data-chapter="'+chapterName+'"]').parent();
if ( !$(this.chapter).hasClass('active-chapter') ){
$('.active-chapter').removeClass('active-chapter');
$('#thumbnail-container').animate({
'scrollLeft' : '+='+thumbnail.position().left
},{
duration : 400,
easing : 'easeOutSine'
});
$(this.chapter).addClass('active-chapter');
}
}
reScale: function() {
var windowHeight = $(window).height() - 20;
if (windowHeight <= 827) {
$('#viewer-container').addClass('scale scale075');
}
}
CSS:
.scale075 {
-webkit-transform: scale(0.75); /* Chrome, Safari 3.1+ */
-webkit-transform-origin: 50% 50%;
-moz-transform: scale(0.75); /* Firefox 3.5+ */
-moz-transform-origin: 50% 50%;
-ms-transform: scale(0.75); /* IE 9 */
-ms-transform-origin: 50% 50%;
-o-transform: scale(0.75); /* Opera 10.50-12.00 */
-o-transform-origin: 50% 50%;
transform: scale(0.75); /* Firefox 16+, IE 10+, Opera 12.10+ */
transform-origin: 50% 50%;
}
Here is a fiddle
$('#thumbnail-container').animate({
'scrollLeft' : thumbnail[0].offsetLeft/*change here*/
},{
duration : 400,
easing : 'easeOutSine'
});
I think,in this ticket,it's better to use absolute position then relative position.
And then offsetLeft has no relation with transform,so everything work fine.
fiddle
You can resolve this if you know the scale in the script.
I modded your fiddle to fix it and tried to fix your example code.
Here is a fiddle
So when you transform to say 0.75 you set a variable to 0.75 then when you set the scrollLeft you multiply the thumbnail position with 1/scale
var scrollScale = 1;
...
scroll: function(){
var chapterName = this.chapter.getAttribute('data-chapter');
var thumbnail = $('.thumbnail-content[data-chapter="'+chapterName+'"]').parent();
if ( !$(this.chapter).hasClass('active-chapter') ){
$('.active-chapter').removeClass('active-chapter');
$('#thumbnail-container').animate({
'scrollLeft' : '+='+thumbnail.position().left * (1/scrollScale)
},{
duration : 400,
easing : 'easeOutSine'
});
$(this.chapter).addClass('active-chapter');
}
}
reScale: function() {
var windowHeight = $(window).height() - 20;
scrollScale = 1;
if (windowHeight <= 827) {
$('#viewer-container').addClass('scale scale075');
scrollScale = 0.75;
}
}
Hope that solves your problem or give you an idea how to solve it more dynamically.
So the reason for this is that position().left uses your transform when it recalculates position.. But scrollLeft dont check transform. so you recalculate position so they use the same scale.

Animating SVG element on viewport

My question is related to my previous question Triggering css animate class on scroll
I am trying to figure out how to trigger the viewport Javascript on the inner SVG element class.
You can see here the example: http://codepen.io/anon/pen/Afqza
<div style="height: 400px;"></div>
<svg version="1.1" id="lock" xmlns="http://www.w3.org/2000/svg" width="85px" height="85px" viewBox="0 0 103 103" ><g><g><g><g><circle style="fill:#E84849;" cx="51.5" cy="51.501" r="51.125"/></g></g></g></g><g><g><g class="shackle"><path style="fill:#CFC7BE;" d="M78.345,46.518c0-14.869-11.813-28.387-26.386-28.387c-14.573,0-26.386,13.518-26.386,28.387h6.829c0-11.021,8.756-21.419,19.557-21.419s19.557,10.398,19.557,21.419H78.345z"/><path style="fill:#E8E7E7;" d="M61.385,20.101v7.816c3.039,1.927,5.583,4.717,7.362,7.975V24.879C66.562,22.886,64.076,21.26,61.385,20.101z"/></g><g><path style="fill:#F4E028;" d="M78.358,79.801c0,3.116-2.579,5.642-5.765,5.642H31.281c-3.186,0-5.764-2.525-5.764-5.642V46.419c0-3.116,52.841-3.116,52.841,0V79.801z"/></g><g><path style="fill:#DAC425;" d="M58.047,59.944c0-3.253-2.638-5.89-5.889-5.89c-3.253,0-5.889,2.637-5.889,5.89c0,2.481,1.536,4.599,3.705,5.468v5.431c0,1.151,0.935,2.084,2.085,2.084c1.153,0,2.086-0.933,2.086-2.084v-5.36C56.418,64.666,58.047,62.498,58.047,59.944z"/></g><g><path style="fill:#D0B82B;" d="M46.048,59.944c0-3.253,2.637-5.89,5.891-5.89c0,0-4.105,2.737-4.105,5.99c0,3.312,3.097,5.276,3.097,5.276v5.581c0,1.153,1.104,2.024,1.104,2.024c-1.15,0-2.085-0.933-2.085-2.084v-5.36C47.677,64.666,46.048,62.498,46.048,59.944z"/></g></g><g><polygon style="fill:#F8E349;" points="68.747,85.442 61.385,85.442 61.385,44.219 68.747,44.585 "/></g></g></svg>
.shackle {
animation-name: open;
-webkit-animation-name: open;
animation-duration: 0.5s;
-webkit-animation-duration: 0.5s;
transform: rotate(0deg);
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
-webkit-transform: rotate(0deg);
transform-origin: bottom left;
}
#keyframes open {
0% {
transform: rotate(0deg);
}
50% {
transform: rotate(-10deg);
}
100% {
transform: rotate(0deg);
}
}
#-webkit-keyframes open {
0% {
-webkit-transform: rotate(0deg);
}
50% {
-webkit-transform: rotate(-10deg);
}
100% {
-webkit-transform: rotate(0deg);
}
}
var onAppear = [];
document.addEventListener("DOMContentLoaded", function() {
onAppear = [].map.call(document.querySelectorAll("#lock"), function(item ) {
return item;
});
}, false);
window.addEventListener("scroll", function() {
onAppear.forEach(function(elem) {
var vwTop = window.pageYOffset;
var vwBottom = (window.pageYOffset + window.innerHeight);
var elemTop = elem.offsetTop;
var elemHeight = elem.offsetHeight;
if (vwBottom > elemTop && ((vwTop - elemHeight) < elemTop)) {
elem.classList.add("shackle");
} else {
elem.classList.remove("shackle");
}
});
}, false);
Currently the whole padlock animates instead of the shackle that I want to animate.
Must be something simple but I cannot figure it out.
The issue is that you arent applying the animation class to the shackle element, you are applying it to the lock element.
Because you are playing around with CSS3 and SVG, I can assume you dont need to accommodate for IE7 and below. Therefore, we can assume it's safe to use JS's querySelector method.
First, we'll update the style definition to indicate the class is for an animation definition (and also to separate it from the class on the shackle element that we'll use to select it).
change .shackle to .animShackle in CSS
Second, we'll need to update the scroll event listener to search within the supplied element for the .shackle classed element, and then apply the animation class to that.
update JS
JS
window.addEventListener("scroll", function() {
onAppear.forEach(function(elem) {
var vwTop = window.pageYOffset;
var vwBottom = (window.pageYOffset + window.innerHeight);
var elemTop = elem.offsetTop;
var elemHeight = elem.offsetHeight;
var shackle = elem.querySelector('.shackle');
if (vwBottom > elemTop && ((vwTop - elemHeight) < elemTop)) {
shackle.classList.add("animShackle");
} else {
shackle.classList.remove("animShackle");
}
});
}, false);
UPDATE
To make the code more extensible to the need for additional elements with their own animations we need to change some of our variable names so that they feel more universal, and update the way we are getting and setting the animation class.
Add a universal class to the animated SVG's so that we can find them in our onAppear function
add class animatedSVG
update querySelectorAll method to use new class rather than single id
Update the class name on the animated element within the SVG so that we can access it within the scroll onAppear.forEach method
update class .shackle to .animatedElement in HTML
update elem.querySelector method to use new class rather than non-generic .shackle
Use the SVG's id attribute to create a classname for animation
add a new variable called animationClass made from the SVG id with 'anim' prepended
HTML now requires the following 3 things:
id attribute on SVG
class="animatedSVG" on SVG
class="animatedElement" on element within SVG you wish to animate
Updated JS
var onAppear = [];
document.addEventListener("DOMContentLoaded", function() {
onAppear = [].map.call(document.querySelectorAll(".animatedSVG"), function(item) {
return item;
});
}, false);
window.addEventListener("scroll", function() {
onAppear.forEach(function(elem) {
var vwTop = window.pageYOffset;
var vwBottom = (window.pageYOffset + window.innerHeight);
var elemTop = elem.offsetTop;
var elemHeight = elem.offsetHeight;
var animatedElem = elem.querySelector('.animatedElement');
var animationClass = 'anim'+elem.id;
if (vwBottom > elemTop && ((vwTop - elemHeight) < elemTop)) {
animatedElem.classList.add(animationClass);
} else {
animatedElem.classList.remove(animationClass);
}
});
}, false);
DEMO

Change value of webkit filter every seconds

I try to change the webkit filter value of element every seconds with this code:
$(document).ready(function () {
console.log("ready!");
function setOpacity() {
var regExp = /\(([^)]+)\)/;
var str = regExp.exec($(".content").css("-webkit-filter"));
var currentValue = str[0].substring(1).slice(0, -1);
console.log(currentValue);
$(".content").css("-webkit-filter", "opacity(" + parseFloat(currentValue) + 0.01 + " %) grayscale(70%);");
}
var t = setInterval(setOpacity, 1000);
});
But the code doesn't work. Where did I make a mistake?
You can use CSS3 keyframe animations to accomplish that. My example is to fade from 0 to 1 (or 0% to 100%, that is) in one second:
.content {
width: 100%;
-webkit-filter: grayscale(70%);
-webkit-animation: fadeIn 1s 0s 1 ease-in-out;
}
#-webkit-keyframes fadeIn {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
The animation shorthand is written in the following order: animation name, duration, delay, iteration, timing-function. The order does not matter except for duration, delay and iteration.
See JSfiddle for proof-of-concept example: http://jsfiddle.net/teddyrised/A85vZ/. You might want to run the fiddle after loading it, because you'll probably miss the animation :)
You could use CSS-transitions for that.
HTML
<div class="content"></div>
CSS
.content{
opacity: 0;
transition-property: opacity;
transition-duration: 2s; /* Short syntax: " transition: opacity 2s;" */
}
.show{
opacity: 1;
}
jQuery
$(document).ready( function(){
$('.content').addClass('show');
});
JSFiddle

Categories