The background:
I have two sliders that are connected.
One shows the thumbnails and scrolls up and down (in a loop) using a wrapper and margin-top. It displays 4 thumbnails at a time.
The other scrolls left and right and displays one single item using display:none; and display: block;.
The sliders are synced, by which I mean if you click the thumbnail the corresponding image in the second slider shows, and if you click next or prev in the big slider the corresponding thumbnail is highlighted. This is working.
The issue:
I am struggeling to add a way to scroll the thumbnail slider to the active item if it is not already in the viewport.
Clicking next on the big slider should only scroll the thumbnail slider if the correct thumbnail is not already in the visible area.
Now, the way I thought I could go about this is the following:
Get the current margin-top of the thumbnail slider.
Get the index of the active item.
Get the supposed marginTop of the index item, as well as the previous and next 3.
If marginTop >= (curindex - 3 * thumbnailHeight)
and marginTop <= 0 - (curindex * thumbnailHeight)
Item should be visible but at the bottom
Or marginTop <= (curindex + 3) * thumbnailHeight
and marginTop >= 0 + (curindex * thumbnailHeight)
Item should be visible at the top.
Combined (for full code see below):
if(((marginTop >= (curindex - 3) * thumbnailHeight) && (marginTop <= 0 - (curindex * thumbnailHeight))) || ((marginTop <= (curindex + 3) * thumbnailHeight) && (marginTop >= 0 + (curindex * thumbnailHeight)))) {
console.log('no scroll');
} else {
scrollWrapper.style.marginTop = 0 - (curindex * thumbnailHeight) + 'px';
}
The error:
There must be some logical flaw that I can not wrap my head around.
The code works fine for the first 4 items, but afterwards it continues to scroll, or if the small slider was already scrolled it also keeps on scrolling downwards. At the end it even overscrolls. The prev function has similar issues, but here it also skips the scroll to the first item.
Full code:
https://jsfiddle.net/Sirence/nuzsryxd/1/
var thumbnailHeight = 92;
var boxCount = 8;
var maxTop = (boxCount - 3) * thumbnailHeight;
var scrollWrapper = document.getElementById('thumbnail-slider');
var thumbnails = document.getElementsByClassName('thumbnail');
var images = document.getElementsByClassName('image');
var curindex = 0;
window.thumbnail = function(index) {
for (i = 0; i < thumbnails.length; ++i) {
thumbnails[i].classList.remove('active');
}
thumbnails[index].classList.add('active');
for (j = 0; j < images.length; ++j) {
images[j].style.display = 'none';
}
images[index].style.display = 'inline-block';
curindex = index;
};
window.down = function() {
marginTop = parseInt(scrollWrapper.style.marginTop, 10);
if(marginTop) {
if(marginTop == (0 - maxTop)) scrollWrapper.style.marginTop = '0px';
else scrollWrapper.style.marginTop = (marginTop - thumbnailHeight) + 'px';
}
else scrollWrapper.style.marginTop = 0 - thumbnailHeight + 'px';
};
window.up = function() {
marginTop = parseInt(scrollWrapper.style.marginTop, 10);
if(marginTop) {
if(marginTop == 0) scrollWrapper.style.marginTop = 0 - maxTop + 'px';
else scrollWrapper.style.marginTop = (marginTop + thumbnailHeight) + 'px';
}
else scrollWrapper.style.marginTop = 0 - maxTop + 'px';
};
window.next = function() {
images[curindex].classList.remove('current');
images[curindex].style.display = 'none';
if (curindex < boxCount) {
curindex++;
} else {
curindex = 0;
}
images[curindex].classList.add('current');
images[curindex].style.display = 'block';
for (i = 0; i < thumbnails.length; ++i) {
thumbnails[i].classList.remove('active');
}
thumbnails[curindex].classList.add('active');
// my problem
var marginTop = parseInt(scrollWrapper.style.marginTop, 10);
if (!marginTop) marginTop = 0;
if(((marginTop >= (curindex - 3) * thumbnailHeight) && (marginTop <= 0 - (curindex * thumbnailHeight))) || ((marginTop <= (curindex + 3) * thumbnailHeight) && (marginTop >= 0 + (curindex * thumbnailHeight)))) {
console.log('no scroll');
} else {
scrollWrapper.style.marginTop = 0 - (curindex * thumbnailHeight) + 'px';
}
};
window.prev = function() {
images[curindex].classList.remove('current');
images[curindex].style.display = 'none';
if (curindex > 0) {
curindex--;
} else {
curindex = boxCount;
}
images[curindex].classList.add('current');
images[curindex].style.display = 'block';
for (i = 0; i < thumbnails.length; ++i) {
thumbnails[i].classList.remove('active');
}
thumbnails[curindex].classList.add('active');
// my problem (same issue as above just the other way around)
var marginTop = parseInt(scrollWrapper.style.marginTop, 10);
if (!marginTop) marginTop = 0;
if(((marginTop >= (curindex - 3) * thumbnailHeight) && (marginTop <= 0 - (curindex * thumbnailHeight))) || ((marginTop <= (curindex + 3) * thumbnailHeight) && (marginTop >= 0 + (curindex * thumbnailHeight)))) {
console.log('no scroll');
} else {
if (curindex >= boxCount - 3) {
scrollWrapper.style.marginTop = 0 - maxTop + 'px';
} else {
scrollWrapper.style.marginTop = 0 - (curindex * thumbnailHeight) + 'px';
}
}
};
* {
margin: 0;
padding: 0;
font-family: sans-serif;
text-align: center;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
#thumbnail-sidebar {
height: 358px;
overflow: hidden;
margin-top: 20px;
margin-bottom: 20px;
border: 1px solid black;
width: 100px;
padding: 10px;
}
.thumbnail {
width: 98px;
height: 80px;
border: 1px solid black;
margin-bottom: 10px;
text-align: center;
line-height: 80px;
cursor: pointer;
}
.thumbnail.active {
border: 1px solid red;
}
.slider-control {
width: 122px;
border: 1px solid black;
cursor: pointer;
}
#thumbnail-slider {
transition: all 0.5s linear;
}
.main-control {
border: 1px solid black;
cursor: pointer;
display: inline-block;
width: 50px;
}
#main {
border: 1px solid black;
display: inline-block;
width: 200px;
height: 200px;
margin-top: 40px;
overflow: hidden;
}
.image {
width: 200px;
height: 200px;
display: none;
font-size: 14px;
box-sizing: border-box;
line-height: 200px;
}
.current {
display: block;
}
<div id="up" class="slider-control" onclick="up()">Up</div>
<div id="thumbnail-sidebar">
<div id="thumbnail-slider">
<div class="thumbnail active" onclick="thumbnail(0)">0</div>
<div class="thumbnail" onclick="thumbnail(1)">1</div>
<div class="thumbnail" onclick="thumbnail(2)">2</div>
<div class="thumbnail" onclick="thumbnail(3)">3</div>
<div class="thumbnail" onclick="thumbnail(4)">4</div>
<div class="thumbnail" onclick="thumbnail(5)">5</div>
<div class="thumbnail" onclick="thumbnail(6)">6</div>
<div class="thumbnail" onclick="thumbnail(7)">7</div>
<div class="thumbnail" onclick="thumbnail(8)">8</div>
</div>
</div>
<div id="down" class="slider-control" onclick="down()">Down</div>
<div id="prev" class="main-control" onclick="prev()">Prev</div>
<div id="main">
<div id="main-slider">
<div class="image current">0</div>
<div class="image">1</div>
<div class="image">2</div>
<div class="image">3</div>
<div class="image">4</div>
<div class="image">5</div>
<div class="image">6</div>
<div class="image">7</div>
<div class="image">8</div>
</div>
</div>
<div id="next" class="main-control" onclick="next()">Next</div>
Related
I'm trying create draggable elements that can also be resized by dragging bottom right corner with the help of resize: both CSS rule.
So far I'm able drag it around screen, but I can't figure out how to detect if cursor at "resize" state, because attempting resize the element moves it instead.
Currently as a work around I'm simply checking if cursor within 20px from bottom-right corner, but that's not very accurate (and probably browser/os dependent), in some places it refuses resize and move the element at all.
Any suggestions?
!function(){
"use strict";
let x, y, drag;
document.addEventListener("mousedown", function(e) {
if (e.target.parentNode.lastChild !== e.target && e.target.parentNode.classList.contains("main")) {
//bring element to the front and dispatch mousedown event again otherwise resize doesn't work
e.target.parentNode.appendChild(e.target);
return e.target.dispatchEvent(new MouseEvent(e.type, e));
}
if (!e.target.classList.contains("draggable"))
return;
/* if cursor within 20px from bottom right corner don't move */
const r = e.target.getBoundingClientRect();
if (r.right < e.x + 20 && r.bottom < e.y + 20)
return;
drag = e.target;
x = e.x - drag.offsetLeft;
y = e.y - drag.offsetTop;
document.body.classList.add("drag");
drag.classList.add("drag");
});
document.addEventListener("mouseup", function(e) {
document.body.classList.remove("drag");
drag = drag && drag.classList.remove("drag");
});
document.addEventListener("mousemove", function(e) {
if (!drag || e.x - drag.offsetLeft == x || e.y - drag.offsetTop == y)
return;
drag.style.left = (e.x - x) + "px";
drag.style.top = (e.y - y) + "px";
});
/*init*/
for (let i = 0, c, d = document.getElementsByClassName("main")[0].children; i < d.length; i++) {
c = (0x1000000 + Math.random() * 0xffffff).toString(16).substr(1, 6);
d[i].style.backgroundColor = '#' + c;
d[i].classList.toggle("dark", ((parseInt(c.substr(0, 2), 16) * 299) + (parseInt(c.substr(2, 2), 16) * 587) + (parseInt(c.substr(4, 2), 16) * 114)) / 1000 < 128);
d[i].style.left = document.documentElement.scrollWidth / 8 + Math.random() * (document.documentElement.scrollWidth / 1.33 - d[i].offsetWidth) + "px";
d[i].style.top = document.documentElement.scrollHeight / 8 + Math.random() * (document.documentElement.scrollHeight / 1.33 - d[i].offsetHeight) + "px";
}
}()
div.main>div {
width: 5em;
height: 5em;
border: 1px solid black;
position: absolute;
resize: both;
overflow: hidden;
mix-blend-mode: hard-light;
display: flex;
border-radius: 0.3em;
}
div.main>div:hover {
box-shadow: 0 0 5px black;
}
div.main>div:last-child {
box-shadow: 0 0 10px black;
}
div.draggable {
cursor: grab;
}
div.main>div:not(.draggable):before {
content: "can't move me";
}
div.main>div.draggable:before {
content: "move me";
}
div.main>div:before {
color: black;
text-shadow: 0 0 1em black;
margin: auto;
text-align: center;
}
div.main>div.dark:before {
color: white;
text-shadow: 0 0 1em white;
}
body.drag {
user-select: none;
}
body.drag div.draggable {
cursor: grabbing;
}
<div class="main">
<div></div>
<div class="draggable"></div>
<div class="draggable"></div>
<div class="draggable"></div>
</div>
You could wrap the mouse-target (.draggable) inside a resizeable container element.
This way, the UI for the CSS-resize will get hit before the draggable element and you can handle only the dragging nicely:
!function(){
"use strict";
let x, y, drag;
document.addEventListener("mousedown", function(e) {
if (e.target.parentNode.lastChild !== e.target && e.target.parentNode.classList.contains("main")) {
//bring element to the front and dispatch mousedown event again otherwise resize doesn't work
e.target.parentNode.appendChild(e.target);
return e.target.dispatchEvent(new MouseEvent(e.type, e));
}
if (!e.target.classList.contains("draggable"))
return;
e.preventDefault();
drag = e.target.parentNode;
x = e.x - drag.offsetLeft;
y = e.y - drag.offsetTop;
document.body.classList.add("drag");
drag.classList.add("drag");
});
document.addEventListener("mouseup", function(e) {
document.body.classList.remove("drag");
drag = drag && drag.classList.remove("drag");
});
document.addEventListener("mousemove", function(e) {
if (!drag || e.x - drag.offsetLeft == x || e.y - drag.offsetTop == y)
return;
drag.style.left = (e.x - x) + "px";
drag.style.top = (e.y - y) + "px";
});
/*init*/
for (let i = 0, c, d = document.getElementsByClassName("main")[0].children; i < d.length; i++) {
c = (0x1000000 + Math.random() * 0xffffff).toString(16).substr(1, 6);
d[i].style.backgroundColor = '#' + c;
d[i].classList.toggle("dark", ((parseInt(c.substr(0, 2), 16) * 299) + (parseInt(c.substr(2, 2), 16) * 587) + (parseInt(c.substr(4, 2), 16) * 114)) / 1000 < 128);
d[i].style.left = document.documentElement.scrollWidth / 8 + Math.random() * (document.documentElement.scrollWidth / 1.33 - d[i].offsetWidth) + "px";
d[i].style.top = document.documentElement.scrollHeight / 8 + Math.random() * (document.documentElement.scrollHeight / 1.33 - d[i].offsetHeight) + "px";
}
}()
.resizeable {
width: 5em;
height: 5em;
border: 1px solid black;
position: absolute;
resize: both;
overflow: hidden;
mix-blend-mode: hard-light;
border-radius: 0.3em;
}
div.main>div:hover {
box-shadow: 0 0 5px black;
}
div.main>div:last-child {
box-shadow: 0 0 10px black;
}
div.draggable {
cursor: grab;
width: 100%;
height: 100%;
display: flex;
}
div.no-drag {
display: flex;
}
div.main div.no-drag:before {
content: "can't move me";
}
div.draggable:before {
content: "move me";
}
div.main div:before {
color: black;
text-shadow: 0 0 1em black;
margin: auto;
text-align: center;
}
div.main>div.dark:before {
color: white;
text-shadow: 0 0 1em white;
}
body.drag {
user-select: none;
}
body.drag div.draggable {
cursor: grabbing;
}
<div class="main">
<div class="resizeable no-drag"></div>
<div class="resizeable"><div class="draggable"></div></div>
<div class="resizeable"><div class="draggable"></div></div>
<div class="resizeable"><div class="draggable"></div></div>
</div>
I'm trying to make an image carousel with center animation. I don't want to use CSS animations, instead I'd like to use jQuery.
By pressing the 'Prev' button the animation will start. One of the slides which will be central begins to grow. I've used jQuery's animate() to animate width and height. Everything works as required except I can't understand why the animation makes the central slide jump.
I have created this sample. If you push the 'Prev' button the animation will start.
var scroll_speed = 4000;
var items_cnt = $('.mg_item').length;
var container_size = $(".main_cnt").innerWidth();
var item_avg_w = container_size / 5;
var item_center_w = ((item_avg_w / 100) * 20) + item_avg_w;
var item_center_h = (item_center_w / 16) * 9 + 30;
var item_w = ((container_size - item_center_w) / 4) - 2;
var item_h = ((item_w / 16) * 9);
var gallery_content = $('.gallery_body').html();
$('.gallery_body').html(gallery_content + gallery_content + gallery_content);
var items_offset = items_cnt * item_w + 14;
$('.gallery_body').css('left', -items_offset);
$('.mg_item').css("width", item_w);
$('.mg_item').css("height", item_h);
//$('.mg_item').css("margin-bottom", (item_center_h - item_h) / 2);
//$('.mg_item').css("margin-top", (item_center_h - item_h) / 2);
//$('.mg_item_с').css("width", item_center_w);
//$('.mg_item_с').css("height", item_center_h);
//document.documentElement.style.setProperty('--center_width', item_center_w + "px");
//document.documentElement.style.setProperty('--center_height', item_center_h + "px");
$('.main_cnt').css("height", item_center_h);
check_visible();
AssignCenter(0);
function gonext() {
AssignCenter(-1);
ZoomIn();
$('.gallery_body').animate({
left: '+=' + (item_w + 2),
}, scroll_speed, "linear", function() {
LoopSlides();
});
}
function goprev() {
AssignCenter(1);
ZoomIn();
$('.gallery_body').animate({
left: '-=' + (item_w + 2),
}, scroll_speed, "linear", function() {
LoopSlides();
});
}
function ZoomIn() {
$('.center').animate({
width: item_center_w + 'px',
height: item_center_h + 'px',
}, scroll_speed, function() {});
}
function LoopSlides() {
var cur_pos = $('.gallery_body').position().left
var left_margin = Math.abs(items_offset * 2 - item_w) * -1;
var right_margin = 0 - item_w;
if (cur_pos < left_margin) {
$('.gallery_body').css('left', -items_offset);
}
if (cur_pos >= 0) {
$('.gallery_body').css('left', -items_offset);
}
check_visible();
AssignCenter(0);
}
function check_visible() {
$('.mg_item').each(function(i, obj) {
var pos = $(this).offset().left;
if (pos < 0 || pos > container_size) {
$(this).addClass("invisible");
$(this).removeClass("active");
} else {
$(this).addClass("active");
$(this).removeClass("invisible");
}
});
}
function AssignCenter(offset) {
var center_slide = $('.active')[2 + offset];
$('.center').each(function(i, obj) {
$(this).removeClass("center");
});
$(center_slide).addClass("center");
//$(center_slide).css("width", item_center_w);
//$(center_slide).css("height", item_center_h);
}
:root {
--center_width: 0px;
--center_height: 0px;
}
.main_cnt {
background-color: rgb(255, 0, 0);
padding: 0px;
overflow: hidden;
margin: 0px;
}
.gallery_body {
width: 500%;
background-color: rgb(128, 128, 128);
position: relative;
}
.mg_item {
width: 198px;
height: 150px;
background-color: blue;
display: inline-block;
position: relative;
margin: -1px;
padding: 0px;
font-size: 120px;
}
.center {
background-color: brown;
/*width: var(--center_width) !important;
height: var(--center_height) !important;*/
}
.item_c {
width: 410px;
height: 150px;
background-color: blueviolet;
display: inline-block;
position: relative;
margin: -1px;
padding: 0px;
font-size: 120px;
}
.video-js .vjs-dock-text {
text-align: right;
}
<script src="https://code.jquery.com/jquery-2.2.0.min.js" type="text/javascript"></script>
<div class="main_cnt">
<div class="gallery_body">
<div class="mg_item">1</div>
<div class="mg_item">2</div>
<div class="mg_item">3</div>
<div class="mg_item">4</div>
<div class="mg_item">5</div>
<div class="mg_item">6</div>
<div class="mg_item">7</div>
</div>
</div>
<br><br>
<button onclick="gonext()">GONEXT</button>
<button onclick="goprev()">GOPREV</button>
<button onclick="check_visible()">CHEVIS</button>
When zooming in the browser, the scaleX() property is not staying consistent. TranslateX() works exactly as it should which is why I'm reaching out.
I am building out a stepped progress bar with the Web Animations API and Vanilla JS, the intention is that there will be a form inserted into this so as we step through form steps the animation/steps will show progress through it.
The issue I am encountering is when I am testing for ADA compliance, specifically when zooming in on the page. And even more specifically, it's only when the zoom percentage is not a multiple of 100. So 100, 200, 300, and 400% work perfectly. But 110, 125, 250%, just to name a few, are having issues. The dot that slides across the screen is working as it should.
The unexpected behavior is in the bar that expands across the screen along with the dot, sometimes it goes too far sometimes it doesn't go far enough. The thing that is really confusing me is that both the bar and the dot are both being "controlled" by the same measurements, which is taking the parent div's width and dividing by 3 and then multiplying by the current step. This is what leads me to assuming the issue is in the scaleX transform. I am still testing this overall in IE, encountering the issue in chrome and firefox.
HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>My stepped progress bar</title>
<link href="style.css" type="text/css" rel="stylesheet" />
<link href="fonts.css" type="text/css" rel="stylesheet" />
<!-- Web Animation API polyfill-->
<script src="https://rawgit.com/web-animations/web-animations-js/master/web-animations.min.js"></script>
</head>
<body>
<section>
<div class="progress__container">
<div class="progress__bar">
<div id="progress__fill" class="step1"></div>
<div class="circ__container">
<div class="circ" id="circ__1"></div>
<div class="circ" id="circ__2"></div>
<div class="circ" id="circ__3"></div>
<div class="circ" id="circ__4"></div>
</div>
<div id="progress__dot" class="prog__1"></div>
</div>
<div class="backBar"></div>
<div class="flexrow">
<span class="stepName tab-1">Account</span>
<span class="stepName tab-2">Frequency</span>
<span class="stepName tab-3">Amount</span>
<span class="stepName tab-4">Taxes</span>
</div>
<div class="button__container">
<button class="buttonStep" id="back">Back</button>
<button class="buttonStep is-active" id="next">Next</button>
</div>
</div>
</section>
<script src="script-api.js"></script>
</body>
</html>
CSS:
/* General Styles */
body {
font-family: Arial, helvetica, sans-serif;
}
/* Slider Bar Animation */
#progress__fill {
height:2px;
position: absolute;
top: 7px;
left: 0;
background-color: darkred;
width: 1px;
}
#progress__dot {
background-color: darkred;
color: #fff;
border-radius: 50%;
height: 8px;
width: 8px;
position: absolute;
text-align:center;
line-height: 8px;
padding: 6px;
top: 0;
font-size: 12px;
}
/* Static Bar Elements */
.progress__container {
width: 600px;
margin: 20px auto;
position: relative;
}
.backBar {
height:2px;
width:96%;
position: absolute;
top: 7px;
left: 2%;
background-color: lightgrey;
}
.progress__bar {
z-index: 100;
position: relative;
width: 96%;
margin: 0 auto;
}
.circ {
background-color: #fff;
border: 2px solid lightgrey;
border-radius: 50%;
height: 8px;
width: 8px;
display: inline-block;
position: absolute;
}
.hide {
visibility: hidden
}
.flexrow {
display: flex;
flex-direction: row;
justify-content: space-between;
}
.circ__container {
padding-top: 3px;
}
.flexrow {
margin-top: 20px;
}
.stepName {
font-size: 12px;
text-align: center;
}
.stepName:first-child {
text-align: left;
}
.stepName:last-child {
text-align: right;
}
.stepName.bold {
font-weight: 600;
}
/* Buttons */
.button__container {
padding-top: 100px;
}
.buttonStep {
background: grey;
color: #fff;
padding: 10px 25px;
border-radius: 10px;
font-size: 16px;
}
#back {
float: left;
}
#next {
float: right;
}
.is-active {
background: darkred;
}
JS:
// give a starting value for the transformation
var slideBarWidth = 0,
slideBarScalePoint = 0,
currentStep = 1,
dot = document.getElementById('progress__dot'),
boxWidth = dot.parentElement.offsetWidth;
// insert the current step number into the progress dot
dot.innerHTML = currentStep;
// place the background dots on the bar
for (var x = 1; x < 5; x++) {
document.getElementById('circ__' + x).setAttribute('style', 'left: ' + ((boxWidth / 3) * (x - 1)) + 'px');
if (x == 4) {
document.getElementById('circ__' + x).setAttribute('style', 'left: ' + (((boxWidth / 3) * (x - 1)) - document.getElementById('circ__' + x).offsetWidth)+ 'px');
}
}
// define the timing for progress dot
var dotTiming = {
duration: 500,
fill: "both",
easing: 'ease-in-out'
}
// define the timing for sliding bar
var barTiming = {
duration: 500,
fill: "both",
easing: 'ease-in-out'
}
var passedTiming = {
fill: "both"
}
// make the first step name bold
document.getElementsByClassName('tab-' + currentStep)[0].classList.add('bold');
// on click fire the animation
document.getElementById('next').addEventListener('click', function() {
// make sure the slider does not go further than it should
if (currentStep > 3){return;}
// define the keyframes for the progress dot
if (currentStep == 3) {
var moveDot = [
{transform: 'translateX(' + ((boxWidth / 3) * (currentStep - 1)) + 'px)'},
{transform: 'translateX(' + (((boxWidth / 3) * (currentStep)) - dot.offsetWidth) + 'px)'}
];
} else {
var moveDot = [
{transform: 'translateX(' + ((boxWidth / 3) * (currentStep - 1)) + 'px)'},
{transform: 'translateX(' + ((boxWidth / 3) * (currentStep)) + 'px)'},
];
}
// define the keyframes for the sliding bar
var slideBar = [
{
transform: 'scaleX(' + ((boxWidth / 3) * (currentStep - 1)) + ')',
transformOrigin: 'left'
},
{
transform: 'scaleX(' + ((boxWidth / 3) * (currentStep)) + ')',
transformOrigin: 'left'
}
];
var showDot = [
{backgroundColor: '#fff', border: '2px solid lightgrey' },
{backgroundColor: 'darkred', border: '2px solid darkred' }
];
// putting the keyframes and timings together (progress dot)
var movingDot = document.getElementById("progress__dot").animate(
moveDot,
dotTiming
);
// putting the keyframes and timings together (sliding bar)
var slidingBar = document.getElementById("progress__fill").animate(
slideBar,
barTiming
);
var passingDot = document.getElementById('circ__' + currentStep).animate(
showDot,
passedTiming
);
// making the animation play forwards
movingDot.playbackRate = 1;
slidingBar.playbackRate = 1;
passingDot.playbackRate = 1;
// starting the animations
movingDot.play();
slidingBar.play();
movingDot.onfinish = passingDot;
// incrementing and setting the step counter
currentStep++;
document.getElementById("progress__dot").innerHTML = currentStep;
if (currentStep > 1) {
document.getElementById('back').classList.add('is-active');
}
if (currentStep > 3) {
document.getElementById('next').classList.remove('is-active');
}
// toggling the bold class for the step names
document.getElementsByClassName('tab-' + (currentStep - 1))[0].classList.remove('bold');
setTimeout(() =>
{
document.getElementsByClassName('tab-' + currentStep)[0].classList.add('bold');
}, 600);
});
document.getElementById('back').addEventListener('click', function() {
// make sure the slider does not go back past the beginning
if (currentStep < 2){return;}
// define the keyframes
if (currentStep == 4) {
var moveDot = [
{transform: 'translateX(' + ((boxWidth / 3) * (currentStep - 2)) + 'px)'},
{transform: 'translateX(' + (((boxWidth / 3) * (currentStep - 1)) - dot.offsetWidth) + 'px)'}
];
} else {
var moveDot = [
{transform: 'translateX(' + ((boxWidth / 3) * (currentStep - 2)) + 'px)'},
{transform: 'translateX(' + ((boxWidth / 3) * (currentStep - 1)) + 'px)'}
];
}
var slideBar = [
{
transform: 'scaleX(' + ((boxWidth / 3) * (currentStep - 2)) + ')',
transformOrigin: 'left'
},
{
transform: 'scaleX(' + ((boxWidth / 3) * (currentStep -1 )) + ')',
transformOrigin: 'left'
}
];
var showDot = [
{backgroundColor: 'darkred', border: '2px solid darkred' },
{backgroundColor: '#fff', border: '2px solid lightgrey' }
];
// putting the keyframes and timings together
var movingDot = document.getElementById("progress__dot").animate(
moveDot,
dotTiming
);
var slidingBar = document.getElementById("progress__fill").animate(
slideBar,
barTiming
);
var passingDot = document.getElementById('circ__' + currentStep).animate(
showDot,
passedTiming
);
// making the animation reverse
movingDot.playbackRate = -1;
slidingBar.playbackRate = -1;
passingDot.playbackrate = -1;
// starting the animation
movingDot.play();
slidingBar.play();
movingDot.onfinish = passingDot;
// decrementing and setting the step counter
currentStep--;
// set the current step number as the number in the progress dot on the page
document.getElementById("progress__dot").innerHTML = currentStep;
if (currentStep < 4) {
document.getElementById('next').classList.add('is-active');
}
if (currentStep < 2) {
document.getElementById('back').classList.remove('is-active');
}
// toggling the bold class for the step names
document.getElementsByClassName('tab-' + (currentStep + 1))[0].classList.remove('bold');
setTimeout(() =>
{
document.getElementsByClassName('tab-' + currentStep)[0].classList.add('bold');
}, 400);
});
I expect the dot and the slider to be aligned as they go across the page, regardless of zoom percentage
In doing some experimenting, I figured out that I could just use "width" to transform the item rather than scaleX. Here is what I ended up using:
next button event:
var slideBar = [
{
width: ((boxWidth / 3) * (currentStep - 1)) + 'px'
},
{
width: ((boxWidth / 3) * (currentStep)) + 'px'
}
];
back button event:
var slideBar = [
{
width: ((boxWidth / 3) * (currentStep - 2)) + 'px'
},
{
width: ((boxWidth / 3) * (currentStep -1 )) + 'px'
}
];
In the custom slider i have created, the handle is moving beyond the container. But i want it to stay within the container limits. We could just do it simple by setting margin-left as offset in CSS. But My requirement is when the handle right end detect the container's end the handle should not be allowed to move anymore. Any help is appreciated. Thanks.
Demo Link: https://jsfiddle.net/mohanravi/1pbzdyyd/30/
document.getElementsByClassName('contain')[0].addEventListener("mousedown", downHandle);
function downHandle() {
document.addEventListener("mousemove", moveHandle);
document.addEventListener("mouseup", upHandle);
}
function moveHandle(e) {
var left = e.clientX - document.getElementsByClassName('contain')[0].getBoundingClientRect().left;
var num = document.getElementsByClassName('contain')[0].offsetWidth / 100;
var val = (left / num);
if (val < 0) {
val = 0;
} else if (val > 100) {
val = 100;
}
var pos = document.getElementsByClassName('contain')[0].getBoundingClientRect().width * (val / 100);
document.getElementsByClassName('bar')[0].style.left = pos + 'px';
}
function upHandle() {
document.removeEventListener("mousemove", moveHandle);
document.removeEventListener("mouseup", upHandle);
}
.contain {
height: 4px;
width: 450px;
background: grey;
position: relative;
top: 50px;
left: 40px;
}
.bar {
width: 90px;
height: 12px;
background: transparent;
border: 1px solid red;
position: absolute;
top: calc(50% - 7px);
left: 0px;
cursor: ew-resize;
}
<div class='contain'>
<div class='bar'></div>
</div>
You need to change
this
document.getElementsByClassName('bar')[0].style.left = pos + 'px';
to this
if(pos > 90){
document.getElementsByClassName('bar')[0].style.left = pos - 90 + 'px';
}
else{
document.getElementsByClassName('bar')[0].style.left = 0 + 'px';
}
since width of your bar is 90px I am subtracting 90.
See this updated fiddle
I'm struggling to find a solution to this and wonder if anyone can help.
I'd like to make a page where an image would disappear over time revealing another image. I'm hoping to achieve this by using the updatesecond/getseconds function. So essentially it would act as a clock, the more minutes/seconds have passed the more it disappears, and have it cycle. For example at the beginning of the day it would be a full image, at 12 it would be half, and at 24hours it would be gone, and repeat. I figure it would be an if else function about the percentage of the page that's left, I just can't figure out how to word it.
Is this possible at all? Any help would be greatly appreciated. Thanks!
Here is the code I'm working with so far. Thank you in advance.
body
{
background-color: #FFF;
padding: 2%;
color: #ccc;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 1em;
}
a
{
color: #FFF;
text-decoration: none;
}
a:hover
{
color: #DCE808;
text-decoration: underline;
}
#mosaic
{
/* background-color: yellow;
font-size: 500px;
color: black;
height: 1310px;
width: 2000px; */
background-image: url('tomorrow4.png');
}
#mosaic span.hover
{
/* background-color: blue;
font-size: 500px;
color: white;
height: 1310px;
width: 2000px;
left: 100px;*/
float: left;
background-image: url('today4.png');
}
and javascript
$(document).ready(function() {
var width = 1400;
var height = 724;
count = 0;
elements = new Array();
var el = $('#mosaic');
el.width(width).height(height);
var horizontal_pieces = 100;
var vertical_pieces = 100;
total_pieces = horizontal_pieces * vertical_pieces;
var box_width = width / horizontal_pieces;
var box_height = height / vertical_pieces;
var vertical_position = 0;
for (i=0; i<total_pieces; i++)
{
var tempEl = $('<span class="hover" id="hover-' + i + '">
</span>');
var horizontal_position = (i % horizontal_pieces) * box_width;
if(i > 0 && i % horizontal_pieces == 0)
{
vertical_position += box_height;
}
tempEl.css('background-position', '-' + horizontal_position + 'px
-' + vertical_position + 'px');
el.append(tempEl);
elements.push(tempEl);
}
elements = shuffleArray(elements);
$('#mosaic .hover').width(box_width).height(box_height);
setInterval(toggleDisplay, 100);
});
function toggleDisplay()
{
var tempEl = elements[count];
var opacity = tempEl.css('opacity');
if(opacity == 0)
{
tempEl.animate({ opacity: 1 })
}
else
{
tempEl.animate({ opacity: 0 })
}
count = (count + 1) % total_pieces;
}
/* shuffleArray source:
http://stackoverflow.com/questions/2450954/how-to-randomize-a-
javascript-array#12646864 */
function shuffleArray(array) {
for (var i = array.length - 1; i > 0; i--) {
var j = Math.floor() * (i + 1);
var temp = array[i];
array[i] = array[j];
array[j] = temp;
}
return array;
}
Do you mean something like this? http://jsfiddle.net/1r5qer56/
I used 4 sectors (as skewY tends to screw up over 90 degrees) and had them set to a size relative to the amount of minutes that have passed since midnight.
If you want to test it, just put a custom number in for time.
My code is below:
HTML
<ul class='pie'>
<li class='slice tr'><div class='slice-contents'></div></li>
<li class='slice br'><div class='slice-contents'></div></li>
<li class='slice bl'><div class='slice-contents'></div></li>
<li class='slice tl'><div class='slice-contents'></div></li>
<ul>
CSS
.pie {
position: relative;
margin: 1em auto;
border: dashed 1px;
padding: 0;
width: 32em; height: 32em;
border-radius: 50%;
list-style: none;
background-image: url('http://lorempixel.com/output/animals-q-c-512-512-4.jpg');
}
.slice {
overflow: hidden;
position: absolute;
top: 0; right: 0;
width: 50%; height: 50%;
transform-origin: 0% 100%;
}
.slice.tr {
transform: rotate(0deg) skewY(-0deg);
}
.slice.br {
transform: rotate(90deg) skewY(0deg);
}
.slice.bl {
transform: rotate(180deg) skewY(0deg);
}
.slice.tl {
transform: rotate(270deg) skewY(0deg);
}
.slice-contents {
position: absolute;
left: -100%;
width: 200%; height: 200%;
border-radius: 50%;
background: lightblue;
}
.slice.tr .slice-contents {
transform: skewY(0deg); /* unskew slice contents */
}
.slice.br .slice-contents {
transform: skewY(0deg); /* unskew slice contents */
}
.slice.bl .slice-contents {
transform: skewY(0deg); /* unskew slice contents */
}
.slice.tl .slice-contents {
transform: skewY(0deg); /* unskew slice contents */
}
JS+jQuery
updateClock();
setInterval(function(){updateClock();}, 60000);//check for updates once per minute
function updateClock(){
var dt = new Date();
var time = (dt.getHours() * 60) + dt.getMinutes();//number of minutes since 00.00
var timeToDegrees = time / 4;//1440 minutes in 24hours, 360 degrees in a circle. 1440 / 4 = 360
if(timeToDegrees < 90){//deal with top right sector
$('.slice.tr').css('transform', 'rotate('+timeToDegrees+'deg) skewY(-'+timeToDegrees+'deg)');
$('.slice.tr .slice-contents').css('transform', 'skewY('+timeToDegrees+'deg)');
}
else if(timeToDegrees < 180){//deal with bottom right sector
var localDeg = timeToDegrees - 90;
$('.slice.tr').eq(0).css('transform', 'rotate(90deg) skewY(-90deg)');
$('.slice.tr .slice-contents').css('transform', 'skewY(90deg)');
$('.slice.br').css('transform', 'rotate('+(90+localDeg)+'deg) skewY(-'+localDeg+'deg)');
$('.slice.br .slice-contents').css('transform', 'skewY('+localDeg+'deg)');
}
else if(timeToDegrees < 270){//deal with bottom left sector
var localDeg = timeToDegrees - 180;
$('.slice.tr').css('transform', 'rotate(90deg) skewY(-90deg)');
$('.slice.tr .slice-contents').css('transform', 'skewY(90deg)');
$('.slice.br').css('transform', 'rotate(180deg) skewY(-90deg)');
$('.slice.br .slice-contents').css('transform', 'skewY(90deg)');
$('.slice.bl').css('transform', 'rotate('+(180+localDeg)+'deg) skewY(-'+localDeg+'deg)');
$('.slice.bl .slice-contents').css('transform', 'skewY('+localDeg+'deg)');
}
else if(timeToDegrees <= 360){//deal with top left sector
var localDeg = timeToDegrees - 270;
$('.slice.tr').css('transform', 'rotate(90deg) skewY(-90deg)');
$('.slice.tr .slice-contents').css('transform', 'skewY(90deg)');
$('.slice.br').css('transform', 'rotate(90deg) skewY(-90deg)');
$('.slice.br .slice-contents').css('transform', 'skewY(90deg)');
$('.slice.bl').css('transform', 'rotate(270deg) skewY(-90deg)');
$('.slice.bl .slice-contents').css('transform', 'skewY(90deg)');
$('.slice.tl').css('transform', 'rotate('+(270+localDeg)+'deg) skewY(-'+localDeg+'deg)');
$('.slice.tl .slice-contents').css('transform', 'skewY('+localDeg+'deg)');
}
}
Taking a look at the code, from what I gather, you're looking for a picture that is covered with another picture, proportional to the length of the day in seconds. Like one picture sliding over another? Like this picture:
Take a look at the jsBin I've created here http://jsbin.com/xevinakihe/edit?html,css,js,output
The meat of the code is the timing and height adjustment:
function setCoverHeight() {
var d = new Date();
var curSecs = d.getHours() * 3600 + d.getMinutes() * 60 + d.getSeconds();
var coverHeight = curSecs * 100 / (24 * 3600);
$('.cover').height(coverHeight + '%');
if (curSecs < 24 * 3600) {
setTimeout(setCoverHeight, 1000);
console.log(coverHeight);
} else {
// reset the cover height to 0%
$('.cover').height(0);
// swap the cover image to the bottom
$('.bottom').css('backround-image', $('.cover').css('background-image'));
// set a new cover image
// ... get from Ajax, array, etc
}
}
setCoverHeight();
That is adjusting the HTML:
<div class="wrapper">
<div class="cover"></div>
<div class="bottom"></div>
</div>
Eventually the day will run out and the cover should be swapped with the bottom image, so that you can cycle through individual daily pictures (ex. 'today.jpg' and 'tomorrow.jpg')
Hope that helps!