How to implement "smart" transform: translate? - javascript

I don`t know how i can perform an image check in a block.
That hard to explain, just follow the link and see for yourself. If you scroll down to the cards, wait few seconds you will seen that image go outside from his start point, like this enter image description here
and leaves behind itself void.
I want to fix this in such a way that the image could not go beyond its own size.
My JavaScript code:
"use strict";
var imgArr = document.getElementsByClassName('imgArr');
[].forEach.call(imgArr, function(item, i, arr) {
// set variables
var randValWidth;
var randValHeight;
// take the width and height of each image
var size = {
'widthImg': arr[i].width,
'heightImg': arr[i].height
};
// set time
setInterval(function() {
// add arguments for tRand() and wRand()
var randW = tRand(-size.widthImg/4, size.widthImg/4);
var randH = wRand(-size.heightImg/4, size.heightImg/4);
// start animation
motionItem();
}, 2000);
// find a random value between min and max values
function tRand(min, max) {
randValWidth = Math.floor(Math.random() * (max - min) + min);
};
function wRand(min, max) {
randValHeight = Math.floor(Math.random() * (max - min) + min);
};
// animate elements
function motionItem() {
arr[i].style.transform = 'translate3d(' + randValWidth + 'px,' + randValHeight + 'px,' + 0 + ')';
};
});
How i can fix it?

It's just an image and CSS, no need for JavaScript for that. For example, the box contain that image have height 100px but the image have height 200px so they let image full in div and after that use translate the image to image to make it move up and down.
.box {
width:900px;
height:400px;
background-color:blue;
}
.img {
width:90%;
height:auto;
position:relative;
animation:4s movingUp infinite linear;
transition:4s;
}
#keyframes movingUp {
0%{
transform:translateY(0px);
}
25% {
transform:translateY(50px);
}
50%{
transform:translateY(100px);
}
75%{
transform:translateY(-50px);
}
100% {
transform:translateY(0px);
}
}
<div class="box">
<img class="img"src="http://res.cloudinary.com/dhue87np7/image/upload/v1508082124/sample.jpg" />
</div>

Related

Javascript won't put array values in CSS syntax

I'm trying to make a slide show using multiple background-images and using the background-position property to animate them. Here is the code:
HTML:
<div class="slide_holder" id="slide_holder"></div>
CSS:
.slide_holder {
float: left;
width: 1440px;
height: 720px;
background-image: url("images/gc-h-s-01.jpg"), url("images/gc-h-s-02.jpg"), url("images/gc-h-s-03.jpg");
background-repeat: no-repeat;
background-size: 100%;
background-position: 0px, 1440px, 2880px;
transition: 1s;
}
JS:
var imageIndex = 1;
var x;
var PosValues = ["0px, 1440px, 2880px", "-1440px, 0px, 1440px", "-2880px, -1440px, 0px"]
startSlides();
function startSlides() {
x = setInterval(IncAndWrite, 1000);
}
function IncAndWrite() {
var i;
document.getElementById("slide_holder").style.backgroundPosition = PosValues[imageIndex];
imageIndex++;
if (imageIndex > 2) {imageIndex = 0;}
}
The concept is that the background-position values for each background-image change every 1s keeping only one image in the visible frame.
The above mentioned code works just fine, but I do not want to write individual position values for different screen sizes (as my website is responsive). So I wrote the following code:
JS:
var imageIndex = 1;
var x;
var UnitRes = 1440;
var PosValues = [
UnitRes*0 + "px, " + UnitRes*1 + "px, " + UnitRes*2 + "px;",
UnitRes*(-1) + "px, " + UnitRes*0 + "px, " + UnitRes*1 + "px;",
UnitRes*(-2) + "px, " + UnitRes*(-1) + "px, " + UnitRes*0 + "px;"]
startSlides();
function startSlides() {
x = setInterval(IncAndWrite, 1000);
}
function IncAndWrite() {
var i;
document.getElementById("slide_holder").style.backgroundPosition = PosValues[imageIndex];
imageIndex++;
if (imageIndex > 2) {imageIndex = 0;}
}
The basic concept is that you put the width of the container in UnitRes and then the values get calculated. But this does not seem to work. The background-position values don't change at all.
What I thought was causing the problem:
In the second case of js code I'm putting a variable value inside an array which I thought is not being converted to a string type while inputing it in the CSS syntax.
What I tried doing:
I used typeof but it is showing the type as string
Then I tried using:
document.getElementById("slide_holder").style.backgroundPosition = PosValues[imageIndex].valueOf();
but still it's not working. I also used alert(PosValues[imageIndex]); to check if the values are ok and they are.
Please help me.
The problem was that in first time you have defined parameters without semicolon ; and in second example you have placed it what broke the script.

Add a transform value to the current transforms that are already on the element?

Let's say I have a div that had translateX and translateY values added dynamically.
<div class="object child0"
style="-webkit-transform: translateX(873.5px) translateY(256px);
width: 50px; height: 50px;">
I want to add rotateY(20deg) to the current transforms, but applying it via
element.style.webkitTransform = "rotateX(20deg)" loses the other values.
Is there a way to add the rotateY without losing the translateX and translateY transforms?
You could use the += operator to append the rotateX(20deg) to the already existing transformation.
el.style.webkitTransform += "rotateX(20deg)";
Note: I have used a different transformation in the below snippet for the visual effect but method is the same.
window.onload = function() {
var el = document.getElementsByTagName("div")[0];
el.style.webkitTransform += "rotateZ(20deg)";
console.log(el.style.webkitTransform);
document.getElementById("changeDeg").onclick = changeDeg; //event handler
}
function changeDeg() {
var el = document.getElementsByTagName("div")[0];
var re = /(rotateZ)(\(.*(?:deg\)))/g; //regex to match rotateZ(...deg)
var newDeg = 40;
if (el.style.webkitTransform.match(re).length != -1) {
el.style.webkitTransform = el.style.webkitTransform.replace(re, '$1(' + newDeg + 'deg)'); // $1 is first capturing group which is "rotateZ"
}
console.log(el.style.webkitTransform);
}
div {
background: red;
margin-bottom: 20px;
}
<div class="display-object child0" style="-webkit-transform: translateX(43.5px) translateY(6px); width: 50px; height: 50px;"></div>
<button id="changeDeg">Change Rotation</button>
I know this topic is a bit old, and there is a great answer above by Harry.
Though here is an addition in case you need to modify the transform again:
It turns out that that css converts the transform string into a matrix, which makes it extremely hard to understand how to modify (Here is a full documentary).
So string manipulation solutions are the shortest. Here are the good news:
You actually can "stack" multiple transformations!
Try this:
let el = document.getElementsByTagName("div")[0];
// first, sync JS transform with current transform style:
const originalMatrix = window.getComputedStyle(el).transform
if(!el.style.transform){
el.style.transform = originalMatrix
}
// Then apply as much transforms as you whish
let myTransform = " rotate(45deg)"
el.style.transform += myTransform
el.style.transform += myTransform
The div will rotate 90 degrees!
for that to work make sure that the element have some transform declatation beforehand (one can use * {"transform: scale(1)"} in the style sheet)
Now What if you whish to revert all your changes?
const originalMatrix = window.getComputedStyle(el).transform
// Do some changes....
el.style.setProperty('transform', originalMatrix)
Finally, here is a working example:
Click on the div to modify it, or on the body to revert it to original:
window.onload= () => {
let el = document.getElementById("myDiv")
const originalMatrix = window.getComputedStyle(el).transform
document.addEventListener('click', e=>{
if(e.target != el){return revert(el)}
// Sync El transform style
if(!el.style.transform){
el.style.transform = originalMatrix
}
// Aplly some more transforms
el.style.transform = el.style.transform
let myTransform = " translate(20px, 20px) rotate(45deg)"
el.style.transform += myTransform
})
function revert(el){
el.style.setProperty('transform', originalMatrix)
}
}
div{
background:green;
height:50px;
width:100px;
transform:translate(50px, 50px);
transition:1s;
}
<body>
Click body to revert him
<div id="myDiv">ClickMe</div>
</body>

Adding paging controls to a full page touch swiper/slider - Hammer.js

CLICK FOR FIDDLE
Below is a fully functional full page touch slider I have created using hammer.js
You can drag, swipe or pan to navigate between pages.
The slider works as expected but I am now trying to create fallback navigation by adding two buttons so paging left and right can occur on click also.
QUESTION
How can the hammer swipe left or right be called on click? (Javascript or jQuery).
CURRENT ATTEMPT
$('#Left').on('click', function() {
HammerCarousel(document.querySelector('.Swiper'), 'Left');
});
FULL CODE
function swipe() {
var reqAnimationFrame = (function () {
return window[Hammer.prefixed(window, "requestAnimationFrame")] || function (callback) {
setTimeout(callback, 1000 / 60);
}
})();
function dirProp(direction, hProp, vProp) {
return (direction & Hammer.DIRECTION_HORIZONTAL) ? hProp : vProp
}
function HammerCarousel(container, direction) {
this.container = container;
this.direction = direction;
this.panes = Array.prototype.slice.call(this.container.children, 0);
this.containerSize = this.container[dirProp(direction, 'offsetWidth', 'offsetHeight')];
this.currentIndex = 0;
this.hammer = new Hammer.Manager(this.container);
this.hammer.add(new Hammer.Pan({ direction: this.direction, threshold: 10 }));
this.hammer.on("panstart panmove panend pancancel", Hammer.bindFn(this.onPan, this));
this.show(this.currentIndex);
}
HammerCarousel.prototype = {
show: function (showIndex, percent, animate) {
showIndex = Math.max(0, Math.min(showIndex, this.panes.length - 1));
percent = percent || 0;
var className = this.container.className;
if (animate) {
if (className.indexOf('animate') === -1) {
this.container.className += ' animate';
}
} else {
if (className.indexOf('animate') !== -1) {
this.container.className = className.replace('animate', '').trim();
}
}
var paneIndex, pos, translate;
for (paneIndex = 0; paneIndex < this.panes.length; paneIndex++) {
pos = (this.containerSize / 100) * (((paneIndex - showIndex) * 100) + percent);
translate = 'translate3d(' + pos + 'px, 0, 0)';
this.panes[paneIndex].style.transform = translate;
this.panes[paneIndex].style.mozTransform = translate;
this.panes[paneIndex].style.webkitTransform = translate;
}
this.currentIndex = showIndex;
},
onPan: function (ev) {
var delta = dirProp(this.direction, ev.deltaX, ev.deltaY),
percent = (100 / this.containerSize) * delta,
animate = false;
if (ev.type == 'panend' || ev.type == 'pancancel') {
if (Math.abs(percent) > 20 && ev.type == 'panend') {
this.currentIndex += (percent < 0) ? 1 : -1;
}
percent = 0;
animate = true;
}
this.show(this.currentIndex, percent, animate);
}
};
var outer = new HammerCarousel(document.querySelector('.Swiper'), Hammer.DIRECTION_HORIZONTAL);
};
$(swipe);
html,
body,
.Page,
.Swiper{
position:relative;
height:100%;
}
.Swiper{
background:#666;
overflow:hidden;
}
.Swiper.animate > .Page{
transition:all .3s;
-webkit-transition:all .3s;
}
.Page{
position:absolute;
top:0;
left:0;
height:100%;
width:100%;
padding:0 10px;
font:42px Arial;
color:#fff;
padding-top:10%;
text-align:center;
}
.Page:nth-child(odd) {
background:#b00;
}
.Page:nth-child(even) {
background:#58c;
}
#Left,
#Right{
position:absolute;
top:0;
height:50px;
width:50px;
background:#fff;
text-align:center;
font:16px/3em Arial;
cursor:pointer;
}
#Left{
left:0;
}
#Right{
right:0;
}
<script src="http://hammerjs.github.io/dist/hammer.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="Swiper">
<div class="Page">PAGE 1<br/>DRAG LEFT</div>
<div class="Page">PAGE 2<br/>SWIPE ME</div>
<div class="Page">PAGE 3<br/>HOLD TO PAN</div>
<div class="Page">PAGE 4<br/>FLICK TO GO BACK</div>
</div>
<div id="Left">Left</div>
<div id="Right">Right</div>
I have crafted a jQuery solution for this that should satisfy the fallback you are looking for.
Some things to consider, though. In your example as well, page re-size is not accounted for. I have not done so in this either to remain consistent and solve the immediate issue, but you will notice I am grabbing the $('.Page').width(); as a variable in this solution. I would recommend re-assigning this value if you do account for re-sizing. Also, a mix of swiping/clicking will throw this off. I assume since you indicated this will be a fallback, the user will receive one of the two experiences. If not, we'll need a way to update tracker on swipe events as well.
You'll notice var tracker = { 'R': 0 }. While naming may not be the best, 'R' will account for how many right "swipes" (navigation clicks) the user has performed in a plus/minus 1 manner
<div id="Left" direction="L">Left</div>
<div id="Right" direction="R">Right</div>
$(function() {
var width = $('.Page').width();
var pages = $('.Page').length;
var tracker = { 'R': 0 }
$('#Right, #Left').click(function() {
$(this).attr('direction') === 'R' ?
((tracker.R < (pages - 1) ? tracker.R += 1 : pages)) :
(tracker.R > 0) ? (tracker.R -= 1) : 0;
$('.Swiper').animate({ 'scrollLeft': $('.Page').width() * tracker.R }, 250)
});
});
JSFiddle Link

Javascript: Memory efficient way to do this effect

I wrote the code in Javascript but any good alternative would do.
EFFECT: onmousemove over the webpage circles of random colors should create wherever the mouse moves. and they have to be added behind a mask image(circles are visible only in the transparent portion of the image which is a logo. thus creating a color paint to create logo onmousemove.
it doesn't work in jsfidde because of its memory intensiveness.
WORKING LINK: http://goo.gl/DNRxO9
I pasted the exact code you can create a new html file with the following code and IT WORKS PERFECT IN FIREFOX ONLY because of its memory intensiveness(lots of divs added in very short time so DOM becomes very very heavy).
<html>
<head>
<style type="text/css">
body{
padding:0;
margin:0;
overflow: hidden;
}
#mask{
width:100%;
height:auto;
position:absolute;
z-index:10;
}
#logo{
width:50%;
height:50%;
margin:auto;
}
.point{
width:0px;
height:0px;
background-color:#ff0000;
position:absolute;
z-index:5;
left:50px;top:50px;
border-width:50px;
border-style: solid;
border-color:red;
border-radius:50px;
opacity:1;
transition: border-width 3s ease-in-out;
}
.no-border{border-width:0px;}
</style>
<script type="text/javascript">
function getRandomColor() {
var letters = '0123456789ABCDEF'.split('');
var color = '#';
for (var i = 0; i < 6; i++ ) {
color += letters[Math.round(Math.random() * 15)];
}
return color;
}
/* OptionalCode: for removing divs after a lot are created */
Element.prototype.remove = function() {
this.parentElement.removeChild(this);
}
NodeList.prototype.remove = HTMLCollection.prototype.remove = function() {
for(var i = 0, len = this.length; i < len; i++) {
if(this[i] && this[i].parentElement) {
this[i].parentElement.removeChild(this[i]);
}
}
}
i=0;
function colors(event){
var x=event.clientX;
var y=event.clientY;
var point = document.getElementsByClassName('point');
document.body.innerHTML += "<div class='point'></div>";
point[i].style.borderColor = getRandomColor();
//point[i].className += ' no-border';
point[i].style.left = x + 'px';
point[i].style.top = y + 'px';
i++;
}
function position(){
var ht = window.getComputedStyle(document.getElementById("mask"), null).getPropertyValue("height");
var ht_num = Number(ht.slice(0,ht.length - 2));
margin_top = (Number(document.body.clientHeight) - ht_num)/2;
document.getElementById('mask').style.marginTop = margin_top + "px";
}
</script>
</head>
<body onload="position();" onmousemove="colors(event)">
<img id="mask" src="http://goo.gl/EqfJ0L">
</body>
</html>
There is one HUGE, HUGE, HUGE performance killer in your code:
document.body.innerHTML += "<div class='point'></div>";
This takes your entire document, throws it away and just inserts everything back again. This is horrible! Remember this for all times and never do this again! ;)
Keep the basic rule in mind, to never add Elements via .innerHTML!
The correct way to go is the following:
// create your new div element
var circleElement = document.createElement("div");
// add all the stuff needed
circleElement.classList.add("point");
circleElement.style.borderColor = getRandomColor();
circleElement.style.left = x + 'px';
circleElement.style.top = y + 'px';
// now append the element to the body
document.body.appendChild(circleElement);
This creates a single div and nicely inserts it as a child-element of the body.
Additionally you can decrease the number of divs drawn by introducing a threshhold:
var lastX=0,lastY=0;
function colors(event){
var x=event.clientX;
var y=event.clientY;
if (Math.abs(lastX - x) + Math.abs(lastY - y) <= 10 ) return;
/* do stuff */
lastX = x;lastY = y;
}
As a third measure you can decrease the size of the image to just hold the mask element and trigger the mousemove only on the image (because divs outside the mask are hidden anyway).
Ultimately, you could kill "old" div-elements when you have reached a certain amount.
I have not included these two last optimizations, but look at the already supersmooth example now!

js code in one html section not working

when you reduce the browser window there will be a different iphone lay out...
When I put the js into one html sections its not working....
but if i put js in fiddle js section its working properly....
can you tell the reason....
the problem is my li tags are not getting values from js...
can you tell whats the reason....
providing my code below....
working code....
http://jsfiddle.net/YZYp5/7/
not working code....
http://jsfiddle.net/YZYp5/3/
<li style="display: table-cell; width: 417px; vertical-align: top; border: 1px solid red; left: -417px; -webkit-transition: 300ms; -webkit-transform: translate(0px, 0px) translateZ(0px);" data-index="1">
the problem is with this function
function translate(index, dist, speed) {
var slide = slides[index];
var style = slide && slide.style;
if (!style) return;
style.webkitTransitionDuration =
style.MozTransitionDuration =
style.msTransitionDuration =
style.OTransitionDuration =
style.transitionDuration = speed + 'ms';
style.webkitTransform = 'translate(' + dist + 'px,0)' + 'translateZ(0)';
style.msTransform =
style.MozTransform =
style.OTransform = 'translateX(' + dist + 'px)';
}
The problem seems to be here:
var style = slide && slide.style;
That will make style a boolean value, not an object. You're probably looking for something like this:
var style = slide && slide.style ? slide.style : {};

Categories

Resources