I have a very long article page that I want to help mobile users scroll on. For very long lists in mobile apps there's usually a alphabetical index that can help users jump to various places in the list. How do I implement something like that for a webapp?
If it helps my stack is angularjs / jquery / phonegap.
Just use angular's built-in $anchorScroll service.
See the live example in angular's official docs. Here are the important pieces of code:
In your view template:
<div id="scrollArea" ng-controller="ScrollCtrl">
<a ng-click="gotoBottom()">Go to bottom</a>
<a id="bottom"></a> You're at the bottom!
</div>
In your controller:
function ScrollCtrl($scope, $location, $anchorScroll) {
$scope.gotoBottom = function (){
// set the location.hash to the id of
// the element you wish to scroll to.
$location.hash('bottom');
// call $anchorScroll()
$anchorScroll();
};
}
iOS7 Style List Navigator
If you want something nice on the phone, I just wrote this iOS7 style list navigator. I think the way Apple solved the problem is very straightforward. So we steal it.
It's written considering that you won't probably scroll the body, because in the many designs I've seen for smartphones, scrolling a container allows you to have fixed headers and footers for Android < 4 without getting mad.
A word of warning: this code is really fresh and untested.
SEE DEMO AND CODE
CSS (extract)
#scrolling {
padding-top: 44px;
overflow: scroll;
-webkit-overflow-scroll: touch;
height: 100%;
}
.menu {
position: fixed;
right: 0;
font-size: 12px;
text-align: center;
display: inline-block;
z-index: 2;
top: 58px;
}
.list .divider {
position: -webkit-sticky; /* will stop the label when it reaches the header */
top: 44px;
}
HTML (extract)
<div id="scrolling">
<ul class="menu">
<li>A</li>
<li>B</li>
<li>C</li>
<!-- etc -->
</ul>
<ul class="list">
<li class="divider" id="a">A</li>
<li>Amelia Webster</li>
<li>Andrew WifKinson</li>
<!-- etc -->
Javascript (zepto/jquery)
$(function() {
$(window).on("touchstart touchmove mouseover click", ".menu a", function(e) {
e.preventDefault();
clearInterval(t);
var steps = 25;
var padding = 68;
var target = $( $(this).attr("href") ).next("li");
if ( target.length > 0 ) {
var scroller = $("#scrolling")[0];
var step = parseInt((target[0].offsetTop - padding - scroller.scrollTop)/steps);
var stepno = 0;
setInterval( function() {
if ( stepno++ <= steps ) {
scroller.scrollTop += step;
} else {
clearInterval(t)
}
}, 20);
};
});
});
It performs a basic check of link validity before attempting the scroll. You can change padding to your needs.
Also, you will notice that we are targeting the first element after the required target. This is because Safari seems to go nuts because of the sticky positioning.
This code uses jQuery/Zepto selectors for the sake of brevity and readability. But these libraries are not really needed to achieve the result. With just a little extra digitation you could easily go dependency-free.
http://codepen.io/frapporti/pen/GtaLD
You can use a toggleable sidebar like this one. Resize your browser to the width of the screen of a mobile phone to understand what I mean.
Then create a directive in angularjs to wrap jQuery's animate function to scroll to a specific part in the article. Like this:
angular.module('yourModule', [])
.directive('scrollTo', function() {
return {
restrict : 'EA',
link: function(scope , element, attr){
$('html, body').animate({
scrollTop: $( attr['href'] ).offset().top
}, 300);
}
};
});
where href will be an id of a specific section in the article. Then all you need to do is apply the directive to the links in the sidebar.
...
<li><a href="#section-1" scroll-to>Jump to section 1</a></li>
...
Hope this helps.
This might be what you're looking for http://www.designkode.com/alphascroll-jquery-mobile/
Haven't used it myself, but seems pretty simple to get going with.
I think something like this could work for you: http://codepen.io/aecend/pen/AsnIE. This is just a basic prototype I put together to answer but I could expand on the concept if needed. Basically, it creates a translucent bar on the right side of the screen, finds each of the headings for articles (which would need to be adapted to suit your needs) and places clickable/tappable anchors to jump to individual articles. When you click one, the page scrolls to that article. I have a few ideas to make this actually usable, but here's the proof of concept.
CSS
#scrollhelper {
position: fixed;
top: 0;
right: 0;
height: 100%;
width: 5%;
background-color: rgba(0,0,0,0.2);
overflow: hidden;
}
#scrollhelper .point {
position: absolute;
display: block;
width: 100%;
height: 10px;
margin: 0 auto;
background-color: rgba(0,0,255,0.5);
}
JavaScript
var articles;
function buildScrollHelp() {
var bodyHeight = $("body").height();
var viewHeight = window.innerHeight;
$("#scrollhelper").html("");
articles.each(function() {
var top = $(this).offset().top;
var element = document.createElement("a");
element.className = "point";
element.href = "#" + $(this).attr("id");
element.style.top = ((top / bodyHeight) * viewHeight) + "px";
$(element).on("click", function(e){
e.preventDefault();
$('html, body').animate({
scrollTop: $($(this).attr("href")).offset().top
}, 500);
});
$("#scrollhelper")[0].appendChild(element);
});
}
$(document).ready(function() {
articles = $("body").children("[id]");
$("body").append("<div id=\"scrollhelper\"></div>");
$(window).resize(function(){
buildScrollHelp();
});
buildScrollHelp();
});
Related
I have an animated skills bar on my website, which fires when the section scrolls into view. Everything is working well so far.
Except when the viewport changes/window resizes the animated bars won't adjust to it and will be too long or to short.
I tried to solve this problem with
$(window).resize(function(){location.reload();
but on mobile viewport it keeps refreshing the page even though I'm just scrolling.
I already searched the net to see if there is a way to just reload the specific jquery function, but couldn't find anything. Or to be honest I didn't quite understood I guess, and couldn't get it working.
Here is what I found: https://css-tricks.com/forums/topic/reload-jquery-functions-on-ipad-orientation-change/
I read there is a way to make the website reload the whole js file. But since I still have other animations on my page, I don't know if this is the best way to do it.
I'm glad if anyone could help me with this. I'm very new to coding and my js/jquery knowledge is still very limited/non-existent.
here is my script for the bar animation
var $meters = $(".meter > span");
var $section = $('#skills .meter');
var $queue = $({});
function loadDaBars() {
$meters.each(function() {
var $el = $(this);
var origWidth = $el.width();
$el.width(0);
$queue.queue(function(next) {
$el.animate({width: origWidth}, 800, next);
});
});
}
$(document).bind('scroll', function(ev) {
var scrollOffset = $(document).scrollTop();
var containerOffset = $section.offset().top - window.innerHeight;
if (scrollOffset > containerOffset) {
loadDaBars();
$(document).unbind('scroll');
}
});
the width for the skillbar is defined via div class and span in %.
Maybe there is a css solution to this?
edit: this is how my html and css code looks like
.meter {
background-color: hsla(54, 73%, 95%, 1);
vertical-align: bottom;
width: 100%;
position: relative;
}
.meter>span {
display: block;
background-color: rgb(241, 233, 166);
position: relative;
overflow: hidden;
}
<div class="col-lg-6 col-md-6 col-sm-6">
<div class="meter">
<span style="width: 50%"></span>
</div>
You remove the style property of the bar once the animation has finished. This way the css rule will apply again:
$el.animate({width: origWidth}, {duration: 800, complete: function (){$el.removeAttr('style')}}, next);
(Assuming the width defined by the css is responsive)
I'm trying to perform the Jquery function below when the element becomes visible in the viewport rather than on the page load. What would I need to change to allow that to happen? I'm using an external JS file to perform the Jquery, so keep that in mind.
Here's a piece of the HTML that is associated with the Jquery function -
<div class="skillbar clearfix " data-percent="70%">
<div class="skillbar-title" style="background: #FF704D;">
<span>Illustrator</span></div>
<div class="skillbar-bar" style="background: #FF704D;"></div>
<div class="skill-bar-percent">70%</div>
</div>
jQuery(document).ready(function(){
jQuery('.skillbar').each(function(){
jQuery(this).find('.skillbar-bar').animate({
width:jQuery(this).attr('data-percent')
},4000);
});
});
I once came across such problem and what I used is waypoints small library.
all you need is to include this library and do:
var waypoint = new Waypoint({
element: document.getElementById('waypoint'),
handler: function(direction) {
console.log('Element is in viewport');
}
})
Using CSS3 transitions instead of jQuery animations might be more performant and simpler. a cheap and nasty way of pushing it out of screen to demonstarate the effect.
There's a couple of things you'll need to do - firstly if you only want the animation to trigger when it's in the viewport then you'll need to check if anything is in the viewport on scroll. Then only update the bars width when it comes into view. If you want the effect to repeat every time it comes into viewport you'll need to set .skillbar-bar's width back to 0 if it's out of the viewport (just add an else statement to the viewport checking if)
I've added a 1000px margin-top and 400px margin-bottom in my example to .skillbar as a cheap and nasty way of demonstrating the effect
(function($){
$(document).ready(function(){
var $els = $('.skillbar'); // Note this must be moved to within event handler if dynamically adding elements - I've placed it for performance reasons
var $window = $(window);
$window.on('scroll', function(){
$els.each(function(){ // Iterate over all skillbars
var $this = $(this);
if($window.scrollTop() > $this.offset().top - $window.height()){ // Check if it's in viewport
$this.find('.skillbar-bar').css({'width' : $this.attr('data-percent')}); // Update the view with percentage
}
});
});
});
}(jQuery));
.skillbar{
margin-top: 1000px;
margin-bottom: 400px;
position: relative
}
.skillbar-bar{
transition: width 4s;
position: absolute;
height: 20px;
}
.skill-bar-percent{
position: absolute;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
Scroll down 1000px :)
<div class="skillbar clearfix " data-percent="70%">
<div class="skillbar-title">
<span>Illustrator</span></div>
<div class="skillbar-bar" style="background: #FF704D; width: 20%"></div>
<div class="skill-bar-percent">70%</div>
</div>
This might work for you.
var el = $('.yourElement'),
offset = el.offset(),
scrollTop = $(window).scrollTop();
//Check for scroll position
if ((scrollTop > offset.top)) {
// Code..
}
see this Fiddle
What i have is few button and div of same class.
When i click a button of a class the div of same class gets scrollIntoView and the .log appears beside the div on its right side.
PROBLEMS
OnClick button the scroll does not happen
The .log does not appear beside div
The small triangle pointer does not appear beside .log
Additions(The thing i want but dont know how do i do it!)
Whenever the .log appears i want it to shake little upand down
which continues to do untill mouseover
After mouseout i want the .log to fadeOut(2000)
FOR downvoters
<button class="a1">Div1</button>
<button class="a2">Div2</button>
<button class="a3">Div3</button>
<button class="a4">Div4</button>
<button class="a5">Div5</button>
<button class="a6">Div6</button>
<div id="container">
<div class="a1">This is div1</div>
<div class="a2">This is div2</div>
<div class="a3">This is div3</div>
<div class="a4">This is div4</div>
<div class="a5">This is div5</div>
</div>
<div class="log">Your have a fatal error.</div>
#container div {
height:250px;
width:250px;
border:2px solid #000;
margin:15px;
}
#container {
margin:20px;
}
.log {
z-index: 1;
display: none;
color: #fff;
background-color: #c04848;
text-align: left;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3);
max-width:270px;
font-size:15px;
padding:10px;
position: absolute;
}
.log:after {
top: 0;
left: -9px;
border-top: 9px solid #c04848;
border-left: 9px solid transparent;
}
$('button').click(function(){
var c = $(this).attr('class');
var div = $('#container div.'+c);
$(document).scrollTo(div, 1000);
log.css({
top : div.position().top + div.height()/2,
left : div.position().left + 20
}).show();
});
Fixed it
$('button').click(function(){
var c = $(this).attr('class');
var div = $('#container div.'+c);
$(document).scrollTop(div.offset().top);
$('.log').css({
top : div.position().top + div.height()/2,
left : div.position().left + 20
}).show();
});
What I did is changed the scrollTo to scrollTop. I have added a selector to log class because most likely you forgot it.
Shaky effect
var inter;
function bounceOn(){
var pos = $('.log').position().left;
$('.log').animate({left: pos+50},500, function(){$('.log').animate({left: pos},500)})
setTimeout(bounceOn, 1000);
}
Try and make something out it maybe?
http://jsfiddle.net/h76jg/6/
All parts of my answer are shown in this JFiddle
In terms of scrollTo, you were probably looking for scrollTop. Try something like this:
scrollTop: div.offset().top
instead of:
$(document).scrollTo(div, 1000);
Although, Just going by what your writing there, I am going to assume you wanted some sort of smooth transition to the div, correct? Try this instead:
$('html, body').animate({
scrollTop: div.offset().top
}, 1000);
This will create a smooth scroll to the div instead of just moving to it.
For the log section, you forgot to reference the log class. Instead, you tried to reference it like a variable, so the interpreter got confused. Try putting the log css call in a reference, like this:
$('.log').css({...
Hope these help!
Edit: Were you intending something like This for the bounce? (up and down?). Either Case, #Dharman has the right idea with his code. You would just want to add another animation (similar to the scrolling), but put a timeout on the end (so the method will continually repeat)
Since i cannot accept anyone's answer coz i dont like em but thanks for an idea of bounce animation that did worked...
now i have created my own Fiddle And it worked perfetly!
$('button').click(function () {
var c = $(this).attr('class');
var div = $('div.' + c);
$('html, body').animate({
scrollTop: div.offset().top
}, 1000); //thanks to Dylan Corriveau
console.log(div.position().left);
$('.log').css({
top: div.position().top + div.height() / 2,
left: div.position().left + div.width() + 50
}).show();
clearTimeout(inter);
setTimeout(bounceOn, 500);
});
$('.log').mouseover(function () {
clearTimeout(inter);
}).mouseout(function () {
$(this).fadeOut(3500);
});
var inter;
//here is the magic!
function bounceOn() {
var pos = $('.log').position().left;
$('.log').animate({
left: pos + 15
}, 50, function () {
$('.log').animate({
left: pos
}, 50)
})
inter = setTimeout(bounceOn, 215);
}
can someone please help me make a floating menu in prototypeJS? I found documentation to do it in jQuery, like here: net.tutsplus.com/tutorials/html-css-techniques/creating-a-floating-html-menu-using-jquery-and-css/ and here: manos.malihu.gr/jquery-floating-menu, but can't figure out where to start for prototypeJS.
So I got it work, sorta. I found documentation here. Here's my code:
<html>
<head>
<title>Prototype examples</title>
<script src="lib/prototype/prototype.js" type="text/javascript"></script>
<script type="text/javascript">
Event.observe(window,'scroll', function(evt){
$('movable').setStyle({ top: 8 + document.viewport.getScrollOffsets().top + 'px' });
});
</script>
<style type="text/css">
#container {
background:#000;
padding:100px 10px 10px;
}
#movable {
position: absolute;
float:left;
width:18.5%;
height: 300px;
background-color: red;
}
#firstDiv {
background:#ccc;
float:right;
height:1200px;
width:80%;
}
.clear-both {clear:both;}
</style>
</head>
<body>
<div id="container">
<div id="movable"> Floating menu</div>
<div id="firstDiv">right</div>
<div class="clear-both"></div>
</div>
</body>
</html>
So now I'm trying to get it so it's not choppy when you scroll, and so the menu doesnt start moving until the scroll has moved down to like 100px vertically or something, so it hooks into place.
Figured it out with some help. Used this tutorial: http://jqueryfordesigners.com/fixed-floating-elements/
But changed it up to use Prototype JS syntax. Here's the code:
var topMenu = $('ELEMENT').cumulativeOffset().top;
Event.observe(window,'scroll', function(evt) {
// what the y position of the scroll is
var y = document.viewport.getScrollOffsets().top;
// console.log(y) // console
// check which browser it's using
if (false) { // newer browsers, could be "false"
if (y >= topMenu) {
// if so, ad the fixed class
$('ELEMENT').addClassName('fixed');
} else {
// otherwise remove it
$('ELEMENT').removeClassName('fixed');
}
}
else { // older browsers, iPad, iPhone
if (y >= topMenu) {
$('ELEMENT').setStyle({ top: (0 + document.viewport.getScrollOffsets().top - topMenu) + 'px' });
}
else {
$('ELEMENT').setStyle({ top: 0 + 'px' });
}
}
});
If you want it to not look choppy, you're going to have to use an animation library. If you're using Prototype, then your best bet is to look into Scriptaculous at http://script.aculo.us/
I'd also recommend using Element.cumulativeOffset on DOM load to get the absolute top offset of the menu. Then each time you scroll the menu element, include this initial padding so the menu doesn't just latch on to the top of the viewport.
One more idea too, if you don't particularly want to use an animation library, you could try making the menu position: fixed. You'll still have to keep updating the position for IE though, as it doesn't support fixed positioning ...
i want to make a draggable image in jquery.
first of all my experience with jquery is 0. having said that let me describe what i want to achieve. i have fixed width/height div. and the image contained inside the div is large in size. so i want the image to be draggable inside that div so that the user can see the entire image.
can someone help. pls be a little elaborate about the procedure considering my jquery fluency.
You can use the following;
$(function() {
$("#draggable").draggable();
});
.container {
margin-top: 50px;
cursor: move;
}
#screen {
overflow: hidden;
width: 200px;
height: 200px;
clear: both;
border: 1px solid black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
<div class="container">
<div id="screen">
<img src="https://picsum.photos/200/200" class="drag-image" id="draggable" />
</div>
</div>
You want the jQuery Draggable UI tool. The code for this, as with all jQuery, is very simple:
$(document).ready(function(){
$("#draggable").draggable();
});
Will create a draggable object from a standard html tag (the IMG in your case). And for limiting it's mobility to a specific region, you would look into its containment option.
Update: "What is '#draggable' and 'ready'"?
'#draggable' represents the element that you want to be able to drag. The hash (#) symbol represents an ID. When you add your image tags, may give give it an id like the following:
<img src="myimage.jpg" id="draggable" />
That will make the javascript above make your image draggable, because it has the '#draggable' id that the jQuery is looking for.
'.ready()' is the method that is automagically raised by your browser once the page is finished loading. Developers are encouraged by the jQuery group to place all jQuery code within this method to ensure all of the elements on the page are completely loaded prior to any jQuery code attempts to manipulate them.
to limit to a region for this example, containment is not much of a help.
I have implemented this for vertical only scroll, needs enhancement for horizontal limit:
stop: function(event, ui) {
var helper = ui.helper, pos = ui.position;
var h = -(helper.outerHeight() - $(helper).parent().outerHeight());
if (pos.top >= 0) {
helper.animate({ top: 0 });
} else if (pos.top <= h) {
helper.animate({ top: h });
}
}
$('#dragMe').draggable({ containment: 'body' });
This code will make it posible to drag the div with the ID of dragMe where ever you want inside the body of the document. You can also write a class or id as containment.
$('#dragMe').draggable({ containment: '#container' });
This code will make the div dragMe able to be draggable inside of the id container.
Hope this helps otherwise you should be able to find your answer here http://jqueryui.com/demos/draggable/
Expanding on the answer from PH. this will provide an elastic bounceback whenever the image is dragged to the point the underlying container is exposed:
stop: function(event, ui) {
var helper = ui.helper, pos = ui.position;
var h = -(helper.outerHeight() - $(helper).parent().outerHeight());
var w = -(helper.outerWidth() - $(helper).parent().outerWidth());
if (pos.top <= h) {
helper.animate({ top: h });
} else if (pos.top > 0) {
helper.animate({ top: 0 });
}
if (pos.left <= w) {
helper.animate({ left: w });
} else if (pos.left > 0) {
helper.animate({ left: 0 });
}
}