Any way to make time interval not clickable in fullcalendar? - javascript

I want time intervals, occupied by events, to be not clickable. If I just set event property editable to false, it does not help: I am still able to click near that event. Any way to make all the time interval, occupied by the event not clickable? Maybe somehow stretch its width to cover the whole day (actually, this would be a desirable behaviour)?

This code will fire if a day is occupied by an event. So in theory you can block a click by doing return false; in that logic.
http://jsfiddle.net/ppumkin/2QAY4/
The code that does the magic needs jquery. and you need this piece of code.
dayClick: function(date, allDay, jsEvent, view) {
if ($('div.fc-event').length > 0) {
//
var containerD = $(this).offset();
var containerH = $(this).height();
var mousex = jsEvent.pageX;
$('div.fc-event').each(function(index) {
var offset = $(this).offset();
if (((offset.left + $(this).outerWidth()) > mousex && offset.left < mousex) && ((offset.top > containerD.top) && (offset.top < (containerD.top + containerH)))) {
alert($(this).html());
//This will only fire if an empty space is clicked
//This will not fire if an event is clicked on a day
}
});
}
else {
//Put code here to do things if no events on a day
alert('There are no events on this day');
}
},

Well, you can stretch the events to the full height of a day, using the following CSS:
.fc-event-skin { height: 60px; }
But I would call that a workarround.
fullCalendar is designed to display multiple events on a day. Hence the bars are small enough to display overlapping events.
A better solution for a booking system would be a calendar that does not support overlapping events. Unfortunately there is none I could recommend.

Related

Using buttons to "simulate" mouse-up, mouse-move, and mouse-down events

Hello
I'm currently working on a project that is very similar to the following codepen that I found a long while ago. It's essential a Tinder-like application;
https://codepen.io/suez/pen/MaeVBy
Within the codepen is the following JavaScript/jQuery:
function pullChange() {
animating = true;
deg = pullDeltaX / 10;
$card.css("transform", "translateX("+ pullDeltaX +"px) rotate("+ deg +"deg)");
var opacity = pullDeltaX / 100;
var rejectOpacity = (opacity >= 0) ? 0 : Math.abs(opacity);
var likeOpacity = (opacity <= 0) ? 0 : opacity;
$cardReject.css("opacity", rejectOpacity);
$cardLike.css("opacity", likeOpacity);
};
$(document).on("mousedown touchstart", ".demo__card:not(.inactive)", function(e) {
if (animating) return;
$card = $(this);
$cardReject = $(".demo__card__choice.m--reject", $card);
$cardLike = $(".demo__card__choice.m--like", $card);
var startX = e.pageX || e.originalEvent.touches[0].pageX;
$(document).on("mousemove touchmove", function(e) {
var x = e.pageX || e.originalEvent.touches[0].pageX;
pullDeltaX = (x - startX);
if (!pullDeltaX) return;
pullChange();
});
$(document).on("mouseup touchend", function() {
$(document).off("mousemove touchmove mouseup touchend");
if (!pullDeltaX) return; // prevents from rapid click events
release();
});
});
What I'm looking to achieve is the implementation of two buttons to "simulate" the mouse dragging. So - if you play with the codepen - you'll see that it's possible to drag the cards left and right. A "like" or "dislike" decision is then made based upon how far left or right it was dragged. Also, if you drag a card too far or too little in one direction, the card will snap to a set point upon release.
I want to give the users an option to click a "Like" or 'Dislike" button instead of dragging. Hitting one of these buttons will then perform the same actions as if the card had been dragged.
Is this simple to do? Can anybody give me any guidance? I've spent a bit of time with this, and can't seem to get it to work, so any help would be greatly appreciated!
Let me know if you need more data or information.
Thanks!
Your question left out the important parts of the code; the pullChange() and release() functions. Since those are the functions that actually control the card moving, you should be able to bind them to a button click with a slight caveat. pullChange() utilizes the DeltaX variable and expects it to be there to tell it how far to move, so you'll need to set this by hand since there won't be a drag event telling it how far.

jQuery scroll event: how to determine amount scrolled (scroll delta) in pixels?

I have this event:
$(window).scroll(function(e){
console.log(e);
})
I want to know, how much I have scroll value in pixels, because I think, scroll value depends from window size and screen resolution.
Function parameter e does not contains this information.
I can store $(window).scrollTop() after every scroll and calculate difference, but can I do it differently?
The "scroll value" does not depend on the window size or screen resolution. The "scroll value" is simply the number of pixels scrolled.
However, whether you are able to scroll at all, and the amount you can scroll is based on available real estate for the container and the dimensions of the content within the container (in this case the container is document.documentElement, or document.body for older browsers).
You are correct that the scroll event does not contain this information. It does not provide a delta property to indicate the number of pixels scrolled. This is true for the native scroll event and the jQuery scroll event. This seems like it would be a useful feature to have, similar to how mousewheel events provide properties for X and Y delta.
I do not know, and will not speculate upon, why the powers-that-be did not provide a delta property for scroll, but that is out of scope for this question (feel free to post a separate question about this).
The method you are using of storing scrollTop in a variable and comparing it to the current scrollTop is the best (and only) method I have found. However, you can simplify this a bit by extending jQuery to provide a new custom event, per this article: http://learn.jquery.com/events/event-extensions/
Here is an example extension I created that works with window / document scrolling. It is a custom event called scrolldelta that automatically tracks the X and Y delta (as scrollLeftDelta and scrollTopDelta, respectively). I have not tried it with other elements; leaving this as exercise for the reader. This works in currrent versions of Chrome and Firefox. It uses the trick for getting the sum of document.documentElement.scrollTop and document.body.scrollTop to handle the bug where Chrome updates body.scrollTop instead of documentElement.scrollTop (IE and FF update documentElement.scrollTop; see https://code.google.com/p/chromium/issues/detail?id=2891).
JSFiddle demo: http://jsfiddle.net/tew9zxc1/
Runnable Snippet (scroll down and click Run code snippet):
// custom 'scrolldelta' event extends 'scroll' event
jQuery.event.special.scrolldelta = {
delegateType: "scroll",
bindType: "scroll",
handle: function (event) {
var handleObj = event.handleObj;
var targetData = jQuery.data(event.target);
var ret = null;
var elem = event.target;
var isDoc = elem === document;
var oldTop = targetData.top || 0;
var oldLeft = targetData.left || 0;
targetData.top = isDoc ? elem.documentElement.scrollTop + elem.body.scrollTop : elem.scrollTop;
targetData.left = isDoc ? elem.documentElement.scrollLeft + elem.body.scrollLeft : elem.scrollLeft;
event.scrollTopDelta = targetData.top - oldTop;
event.scrollTop = targetData.top;
event.scrollLeftDelta = targetData.left - oldLeft;
event.scrollLeft = targetData.left;
event.type = handleObj.origType;
ret = handleObj.handler.apply(this, arguments);
event.type = handleObj.type;
return ret;
}
};
// bind to custom 'scrolldelta' event
$(window).on('scrolldelta', function (e) {
var top = e.scrollTop;
var topDelta = e.scrollTopDelta;
var left = e.scrollLeft;
var leftDelta = e.scrollLeftDelta;
// do stuff with the above info; for now just display it to user
var feedbackText = 'scrollTop: ' + top.toString() + 'px (' + (topDelta >= 0 ? '+' : '') + topDelta.toString() + 'px), scrollLeft: ' + left.toString() + 'px (' + (leftDelta >= 0 ? '+' : '') + leftDelta.toString() + 'px)';
document.getElementById('feedback').innerHTML = feedbackText;
});
#content {
/* make window tall enough for vertical scroll */
height: 2000px;
/* make window wide enough for horizontal scroll */
width: 2000px;
/* visualization of scrollable content */
background-color: blue;
}
#feedback {
border:2px solid red;
padding: 4px;
color: black;
position: fixed;
top: 0;
height: 20px;
background-color: #fff;
font-family:'Segoe UI', 'Arial';
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id='feedback'>scrollTop: 0px, scrollLeft: 0px</div>
<div id='content'></div>
Note that you may want debounce the event depending on what you are doing. You didn't provide very much context in your question, but if you give a better example of what you are actually using this info for we can provide a better answer. (Please show more of your code, and how you are using the "scroll value").
To detemine how many pixels were scrolled you have to keep in mind that the scroll event gets fired almost every pixel that you move. The way to accomplish it is to save the previous scrolled value and compare that in a timeout. Like this:
var scrollValue = 0;
var scrollTimeout = false
$(window).scroll(function(event){
/* Clear it so the function only triggers when scroll events have stopped firing*/
clearTimeout(scrollTimeout);
/* Set it so it fires after a second, but gets cleared after a new triggered event*/
scrollTimeout = setTimeout(function(){
var scrolled = $(document).scrollTop() - scrollValue;
scrollValue = $(document).scrollTop();
alert("The value scrolled was " + scrolled);
}, 1000);
});
This way you will get the amount of scrolled a second after scrolling (this is adjustable but you have to keep in mind that the smooth scrolling that is so prevalent today has some run-out time and you dont want to trigger before a full stop).
The other way to do this? Yes, possible, with jQuery Mobile
I do not appreciate this solution, because it is necessary to include heavy jQuery mobile. Solution:
var diff, top = 0;
$(document).on("scrollstart",function () {
// event fired when scrolling is started
top = $(window).scrollTop();
});
$(document).on("scrollstop",function () {
// event fired when scrolling is stopped
diff = Math.abs($(window).scrollTop() - top);
});
To reduce the used processing power by adding a timer to a Jquery scroll method is probably not a great idea. The visual effect is indeed quite bad.
The whole web browsing experience could be made much better by hiding the scrolling element just when the scroll begins and making it slide in (at the right position) some time after. The scrolling even can be checked with a delay too.
This solution works great.
$(document).ready(function() {
var element = $('.movable_div'),
originalY = element.offset().top;
element.css('position', 'relative');
$(window).on('scroll', function(event) {
var scrollTop = $(window).scrollTop();
element.hide();
element.stop(false, false).animate({
top: scrollTop < originalY
? 0
: scrollTop - originalY + 35
}, 2000,function(){element.slideDown(500,"swing");});
});
});
Live demo here

Fullcalendar v2: How to maintain the same scroll time when navigating weeks?

On Fullcalendar 2, when I navigate between weeks, I'd like to maintain the same time ranges in the vertical scroll. For example, in the below images, I am initially looking at times from 12am-3pm. But when I press the next arrow to go to the next week, it resets at 8am.
I know that I can change the default starting time with
scrollTime: "08:00:00",
but how do I make it so that the vertical time range is "fixed" to what I am on?
Unfortunately this is not build-in functionality. There is a workaround but you will always have a little bit of flickering when you go to the previous/next week.
var scroll = -1,
viewNames = ['agendaWeek', 'agendaDay'];
$('#calendar').fullCalendar({
//...
eventAfterAllRender: function(view) {
if(scroll > -1 && viewNames.indexOf(view.name) !== -1)
//Use a setTimeout hack here because the scrollTime will be set after eventAfterAllRender is processed.
setTimeout(function(){
document.querySelector('.fc-agenda-slots').parentNode.parentNode.scrollTop = scroll;
}, 0);
},
viewDestroy: function(view) {
if(viewNames.indexOf(view.name) !== -1)
scroll = document.querySelector('.fc-agenda-slots').parentNode.parentNode.scrollTop;
}
//...
});
jsfiddle
This code will work for FullCalendar v2. It assumes that the scrolling div is the parent of the parent of the .fc-agenda-slots div.
Working Code compatible with fullcalendar 2.6.1
I started this code from the post below (A1rPun).
Working JSFiddle
var scroll = -1;
$('#calendar').fullCalendar({
// init calendar
header: {left: 'today prev,next, refresh title',
right: 'agendaDay,agendaWeek'},
allDaySlot: false,
defaultView: 'agendaDay',
// when all the events are rendered, scroll to the previous saved scroll position
eventAfterAllRender: function(view) {
if(scroll > -1 && (view.name=='agendaDay' || view.name=='agendaWeek'))
setTimeout(function(){
document.querySelector('.fc-scroller').scrollTop = scroll;
},0);
},
// when view is destroyed, we keep the scroll position in a variable
viewDestroy: function(view) {
if(view.name=='agendaDay' || view.name=='agendaWeek')
scroll = document.querySelector('.fc-scroller').scrollTop;
}
}); // end calendar
This solution is working in 'agendaDay', and 'agendaWeek' views.
It's also working when you switch between them.
I don't think it is very pretty because you need to wait until after all the events are rendered.
The more events you have on your calendar, the more time the scroll will take..
A good solution would be to use the
Fullcalendar option scrollTime
You can set it in viewRender like this.
That will have the effect to make the calendar scroll to this time.
viewRender: function(view, element){
view.options.scrollTime = '09:00:00';
}
Maybe there is a way to convert the scroll value into time and then render it to the calendar.
EDIT 1
I figured out that is way much better to use the
viewRender
callback, instead of the eventAfterAllRender callback to set the scroll position.
Here is the JSFiddle
viewRender: function(view, element){
if(scroll > -1 && (view.name=='agendaDay' || view.name=='agendaWeek')){
setTimeout(function(){
document.querySelector('.fc-scroller').scrollTop = scroll;
},0);
}
},
It's allowing to switch between other wiews (month, basicWeek...) and keep saving the scroll.
And it's a bit faster
What I have is:
var height = $(window).scrollTop();
console.log("current height " + height);
$('#calendar').fullCalendar( 'removeEvents');
$('#calendar').fullCalendar( 'addEventSource', e);
$('#calendar').fullCalendar( 'addEventSource', holiday);
$('#calendar').fullCalendar( 'refetchEvents');
window.scrollTo(0,height);
console.log("scroll to " + height);
and it works for me
Here you can set basic configuration.
scrollTime: '08:00:00',
minTime: '00:00:00', // Set your min time
maxTime: '24:00:00', // Set your max time
yes, main thing is 'height' parameter should not be there in calendar configuration.
Remove below parameter
height: 'auto'
While I would like to see this as build-in function, this is the fastest and at the same time less verbose solution I found:
viewDestroy: function (view) {
if (view.name=='agendaDay' || view.name=='agendaWeek') {
var scrollEl = document.querySelector('.fc-scroller');
var scrollFraction = scrollEl.scrollTop / scrollEl.scrollHeight;
this.scrollTime = moment().startOf('day').add(3600 * 24 * scrollFraction, 's').format('HH:mm:00');
view.options.scrollTime = this.scrollTime;
}
}
Notice that this assumes the scroll range is 12AM-12AM. If you limit your visible area, you should adapt the day duration as well.
You can try it out: JSFiddle
give a unique class to event object. add this code in after event render method.
it will scroll to that specific event
$('.fc-scroller').animate({
scrollTop: $('write here unique class of event').position().top
});
To avoid any scroll "flicking", I did this this way (in fullCalendar 2.9.1) :
viewDestroy: function( aView ) {
// At first view date change, get height of an hour
if( !lineHeight )
lineHeight = $('#calendar').find( "tr.fc-minor" ).height() * 2;
// then convert current scroll to hour decimal
var lScrollCurrHour = Math.max( ($('#calendar').find( ".fc-scroller" )[0].scrollTop - 1) / lineHeight, 0 );
// finally, use moment() to convert to a formatted date
aView.options.scrollTime = moment().startOf('day')
.add(lScrollCurrHour, "hours").format("HH:mm:ss");
}
It will keep separated the scroll for week and days agendas
Hope it helps :o)
you could use this to make the scroll time as your desired time.
customButtons:{
PreviousButton: {
text: 'Prev',
icon: 'left-single-arrow',
click: function() {
$('#calendar').fullCalendar('prev');
$("#calendar").fullCalendar( 'scrollTime',"08:00:00" );
}
}
}`
The method I specified here is only for previous button. Likewise we can have custom button for all the default buttons in full calendar and we can add this method to scroll the time whenever needed.
i hope this would help.

Start animation on progress bar when its visible on screen

I want to create a webpage that contains several sections. In one of those sections are something like progress bars. These progress bars are 'animated' so that the user sees them loading on the screen as shown in the example.
Example here
Now this is working as it is but my problem is this:
I want the progress bars to start loading when the bars become visible on the screen.
Once the user scrolls down and gets them in the middle of the screen, the 'animation' should start. The way it is now the animation starts on page load, but the bars are not yet visible as in the following fiddle:
Fiddle
A little extra would be that each bar starts loading after the previous is finished.
I found some similar questions on stack but the answer does not suffice to my needs:
Animate progress bar on scroll & Run animation when element is visible on screen
I tried stuff like (it's not the actual code but it's what I remember of it):
var target = $("#third").offset().top;
var interval = setInterval(function() {
if ($(window).scrollTop() >= target) {
//start loading progress bar
}
}, 250);
But without any good results.
Can anyone help me on this matter?
Thanks in advance!
Here is a fiddle: http://jsfiddle.net/rAQev/4/
I've used a comparison of scroll offset and your special section offset to detect a moment when this section becomes visible.
Animations are queued to be processed one after another using jQuery queue function, you can read about it in jQuery docs (http://api.jquery.com/queue/).
Also scroll event is unbinded when the first 'loading' happens, not to run 'loading' again and again on scroll event when section is visible.
Here is an updated fiddle http://jsfiddle.net/9ybUv/
This one allows for all the progress bars to run at the same time. If you were like me and had 5 or more it takes a long time to do one, then the next, then the next.
$(function() {
var $section = $('#third');
function loadDaBars() {
$(".meter > span").each(function() {
$(this)
.data("origWidth", $(this).width())
.width(0)
.animate({
width: $(this).data("origWidth")
}, 1200);
});
}
$(document).bind('scroll', function(ev) {
var scrollOffset = $(document).scrollTop();
var containerOffset = $section.offset().top - window.innerHeight;
if (scrollOffset > containerOffset) {
loadDaBars();
// unbind event not to load scrolsl again
$(document).unbind('scroll');
}
});
});
Let me try something
function startProgressBar() {
$(".meter > span").each(function() {
$(this)
.data("origWidth", $(this).width())
.width(0)
.animate({
width: $(this).data("origWidth")
}, 1200);
});
}
$(window).scroll(function() {
var target = $('#third');
var targetPosTop = target.position().top; // Position in page
var targetHeight = target.height(); // target's height
var $target = targetHeight + targetPosTop; // the whole target position
var $windowst = $(window).scrollTop()-($(window).height()/2); // yes divided by 2 to get middle screen view.
if (($windowst >= $targetPosTop) && ($windowst < $target)){
// start progressbar I guess
startProgressBar();
}
});
Give it a try, let me know.

without jquery i need to find out if the mouse is over an element, not determine when it becomes over (in case it doesn't move to trigger onmouseover)

without jquery
basically what I am looking for is the ability to see if the mouse is over a div when a countdown finishes
if the user is over the div then perform action for that div
onmouseover only triggers when the mouse crosses the threshold of the div, if the mouse hasn't moved it wouldn't trigger, so that wouldn't work
I need to determine if the mouse is currently over a div at a specific point in time, if it has moved or not from the starting point
all of my hunting has only found onmousover, and nothing to see if the mouse just happens to be there to begin with
I don't have the javascript skills to determine overall coords of div, then map mouse coords and see if it fits there... which is what I believe I need to do
After reading the second answer (the one with millions of a elements) on this SO question, I've came up with this method works without moving the mouse on page load, without involving millions of elements.
HTML
<div id=t></div>
CSS
#t {
/* for illustrative purposes */
width: 10em;
height: 5em;
background-color: #0af;
}
#t:hover {
border-top-style: hidden;
}
JavaScript
document.addEventListener('click', function () {
var c = window.getComputedStyle(document.getElementById('t')).getPropertyValue('border-top-style');
if (c === 'hidden') {
alert('Mouse in box');
} else {
alert('Mouse not in box');
}
}, false);
As stated earlier, bind to the finish event of your countdown instead of the click event on the document.
You may also use any CSS style that's changed on :hover, I chose border-top-style as it is conspicuous. If you're using a border, choose something else.
Here's a jsFiddle.
set a flag to true onmouseover and to false onmouseleave. when countdown finishes if flag is true then it is over element.
HTML
<div id="div-name">the section of the code i am working with has a countdown timer, when it reaches 0 i need to know if the mouse is over a specific box</div>
<button id="notification" onclick="javascript: letsCountIt(5);">click to start countdown</button>
JS
window.ev = false;
document.getElementById('div-name').onmouseover = function () {
window.ev = true;
console.log(window.ev);
}
document.getElementById('div-name').onmouseout = function () {
window.ev = false;
console.log(window.ev);
}
window.letsCountIt = function (cdtimer) {
cdtimer--;
document.getElementById('notification').innerHTML = cdtimer;
if (cdtimer == 0) {
if (window.ev === true) {
alert('over');
} else {
alert('not over');
}
} else {
setTimeout(function(){letsCountIt(cdtimer);}, 1000);
}
}
Look into document.elementFromPoint . When you pass an x,y to elementFromPoint, it will return whatever element (or <body>, if no other specific element) is at that point. You can easily check if this element is the element you want.
The problem then is finding out what point your mouse is at. How to get the mouse position without events (without moving the mouse)? seems to say - don't. At least use mouseMove to track the cursor. The linked question gives examples of how to do so. (Look to the lower scoring answers, as the higher ones only got points for being snarky.)
Just want to say that, I think jQuery's mouseenter and mouseleave events would make this a lot easier, but if you can't use them, maybe this will help you.
Depending on how your page is laid out, this may not be too difficult. You can get the position of your element using the following. Quoting from another answer
element.offsetLeft and element.offsetTop are the pure javascript
properties for finding an element's position with respect to its
offsetParent; being the nearest parent element with a position of
relative or absolute
So, if your element is positioned relatively to the body, so far so good (We don't need to adjust anything).
Now, if we attach an event to the document mousemove event, we can get the current coordinates of the mouse:
document.addEventListener('mousemove', function (e) {
var x = e.clientX;
var y = e.clientY;
}, false);
Now we just need to determine if the mouse falls within the element. To do that we need the height and width of the element. Quoting from another answer
You should use the .offsetWidth and .offsetHeight properties. Note
they belong to the element, not .style.
For example:
var element = document.getElementById('element');
var height = element.offsetHeight;
var width = element.offsetWidth;
Now we have all the information we need, and just need to determine if the mouse falls within the element. We might use something like this:
var onmove = function(e) {
var minX = element.offsetLeft;
var maxX = minX + element.offsetWidth;
var minY = element.offsetTop;
var maxY = minY + element.offsetHeight;
if(e.clientX >= minX && e.clientX <= maxX)
//good horizontally
if(e.clientY >= minY && e.clientY <= maxY)
//good vertically
}
This code works, but the mouse has to be moved once after page load.
var coords;
var getMouseCoordinates = function (e) {
'use strict';
return {
x: e.clientX,
y: e.clientY
};
};
document.addEventListener('mousemove', function (e) {
coords = getMouseCoordinates(e);
}, false);
document.addEventListener('click', function () {
var divCoords = document.getElementById('t').getBoundingClientRect();
if (coords.x >= divCoords.left && coords.x <= divCoords.right && coords.y >= divCoords.top && coords.y <= divCoords.bottom) {
alert('Mouse in box');
} else {
alert('Mouse not in box');
}
}, false);
You wouldn't bind to the click event of document, but rather the finish event of your countdown.
Here's an example. Try clicking in the output window.
You don't need any coordinates or mouse events, if you know a selector for that element:
if (document.querySelector('#elementSelector:hover')) {
alert('I like it when you touch me!');
}

Categories

Resources