Right to Left Horizontal Timeline isn't working as expected - javascript

I've created a jQuery plugin to create a Horizontal Timeline. Now I'm trying to add a Right to Left (RTL) option. I've managed to swap round most of the functions so it's going right to left, but I'm struggling to get the scrolling of the timeline to work as intended. I've made a jsfiddle
The piece of code I'm stuck on is this:
Timeline.prototype._updateTimelinePosition = function (event, timelineComponents) {
if (this.settings.useRTL == false) {
// Get the css left value of the targeted event date
var eventLeft = Number(event.css('left').replace('px', '')),
// Get the width value of the .events-wrapper
timelineWidth = timelineComponents['timelineWrapper'].width(),
// Get the width value of the events (previously set)
timelineTotalWidth = timelineComponents['eventsWrapper'].width();
this._translateTimeline(timelineComponents, - eventLeft + timelineWidth/2, timelineWidth - timelineTotalWidth);
}
else {
/* RTL */
// Get the css left value of the targeted event date
var eventRight = Number(event.css('right').replace('px', '')),
// Get the width value of the .events-wrapper
timelineWidth = timelineComponents['timelineWrapper'].width(),
// Get the width value of the events (previously set)
timelineTotalWidth = timelineComponents['eventsWrapper'].width();
// This line here...
this._translateTimeline(timelineComponents, - eventRight + timelineWidth/2, timelineWidth - timelineTotalWidth);
}
}
Timeline.prototype._translateTimeline = function (timelineComponents, value, totalTranslateValue) {
// Only negative translate value
if (this.settings.useRTL == false) var value = (value > 0) ? 0 : value;
/* RTL*/
// This line here...
else var value = (value > 0) ? 0 : value;
// Do not translate more than timeline width
if (this.settings.useRTL == false)
value = (!(typeof totalTranslateValue === 'undefined') && value < totalTranslateValue ) ? totalTranslateValue : value;
/* RTL */
// This line here...
else value = (!(typeof totalTranslateValue === 'undefined') && value < totalTranslateValue ) ? totalTranslateValue : value;
this._setTransformValue(timelineComponents['eventsWrapper'], 'translateX', value+'px');
// Disable the buttons if necessary
this._buttonDisable(timelineComponents, value, totalTranslateValue);
}
Where I've commented "This line here" on the RTL part is the lines I'm stuck with. I've tried so many variations of code: swapping round all the variables, swapping round all the operands and nothing seems to work correctly.
Basically what I am wanting is the Left to right functionality flipped round for right to left, both of which can be found in the jsfiddle.
The line: this._translateTimeline(timelineComponents, - eventRight + timelineWidth/2, timelineWidth - timelineTotalWidth); in _updateTimelinePosition function, is the function call to translate/move the timeline, calculating the translate value as the second argument. The timeline uses the transform: translate() css to translate/move the timeline along. I can't get it to get calculate properly for right to left.
Expectation:
In the RTL timeline, when clicking prev/next and event buttons the timeline
should automatically scroll along to the correct selected event.
The timeline should start from the right, but sometimes calculates
this wrong.

Related

JavaScript gallery to close (instead of loop), when gallery end/beginning is reached

Plase see title. I would like to achieve the following:
1. On Mobile: In PhotoSwipe, when a swipe to view next image is detected (when already viewing last image), Close PhotoSwipe.
2. On Mobile: Same as the above but when viewing the 1st image. When already viewing 1st image and swipe to show the previous image is detected, Close PhotoSwipe.
3. On Desktop: Using the code below, when the 1st image is viewed, the left arrow PhotoSwipe UI button gets hidden (because there is no previous image to show) and the left arrow key of the keyboard gets disabled.
The goal here is when viewing the first image and the left arrow key on the keyboard is pressed, instead of doing nothing (or looping to the last image), PhotoSwipe gallery to close itself.
Here is a jsfiddle showing the current state of the code:
https://jsfiddle.net/bezq08oc/
Perhaps an approach could be to re-enable loop and in its place to inject code to close the gallery instead of looping it?
loop: false
I am using the code below to:
Hide the not needed arrow when viewing first image or last image.
Disable left and right arrow keys on the keyboard when viewing first image or last image.
This will hide the left arrow on first image and right arrow on last image.
It will also work when the keyboard left and right keys are used to change the images.
// Initialize PhotoSwipe
var gallery = new PhotoSwipe($pswp, PhotoSwipeUI_Default, container, options);
gallery.init();
// disable html-arrows control (Hide left arrow on first image and right arrow on last image)
// Code below works only when PhotoSwipe Gallery loads
gallery.getCurrentIndex() === 0 ? $('.pswp__button--arrow--left').hide() : $('.pswp__button--arrow--left').show();
gallery.getCurrentIndex()+1 === gallery.items.length ? $('.pswp__button--arrow--right').hide() : $('.pswp__button--arrow--right').show();
// disable html-arrows control (Hide left arrow on first image and right arrow on last image)
// Code below works when PhotoSwipe Gallery is already opened
gallery.listen('beforeChange', function() {
gallery.getCurrentIndex() === 0 ? $('.pswp__button--arrow--left').hide() : $('.pswp__button--arrow--left').show();
gallery.getCurrentIndex()+1 === gallery.items.length ? $('.pswp__button--arrow--right').hide() : $('.pswp__button--arrow--right').show();
}
);
// disable keys left+right control
$('body').keydown(function(e) {
// key left
if ((e.keyCode || e.which) == 37) {
if (gallery.getCurrentIndex() === 0) {
gallery.options.arrowKeys = false;
} else {
gallery.options.arrowKeys = true;
}
}
// key right
if ((e.keyCode || e.which) == 39) {
if (gallery.getCurrentIndex()+1 === gallery.items.length) {
gallery.options.arrowKeys = false;
} else {
gallery.options.arrowKeys = true;
}
}
});
Okay, you can do it, but you're going to have to edit the core photoswipe.js file. Delete the code for your previous attempts to do this such as making the key presses do nothing and leave the loop option turned ON for this to work properly.
Part One: In that file find this code on line 1076:
next: function() {
self.goTo( _currentItemIndex + 1);
},
prev: function() {
self.goTo( _currentItemIndex - 1);
},
This is determining the action whenever a user is changing the slide to previous or next through a click or key press. So we can insert a simple statement here checking if it is the first slide, and moving left, or if it is the last slide, and moving right. Then initiate the close function.
So, change the previously mentioned code to this:
next: function() {
if ( (_currentItemIndex + 1) === _getNumItems() ) {
self.close();
} else {
self.goTo( _currentItemIndex + 1);
}
},
prev: function() {
if ( (_currentItemIndex + 1) === 1) {
self.close();
} else {
self.goTo( _currentItemIndex - 1);
}
},
Part Two: We need to also change the mechanism for the swipe gesture, so find this code on line 2306:
if(gestureType === 'swipe') {
var totalShiftDist = _currPoint.x - _startPoint.x,
isFastLastFlick = _releaseAnimData.lastFlickDist.x < 10;
// if container is shifted for more than MIN_SWIPE_DISTANCE,
// and last flick gesture was in right direction
if(totalShiftDist > MIN_SWIPE_DISTANCE &&
(isFastLastFlick || _releaseAnimData.lastFlickOffset.x > 20) ) {
// go to prev item
itemsDiff = -1;
} else if(totalShiftDist < -MIN_SWIPE_DISTANCE &&
(isFastLastFlick || _releaseAnimData.lastFlickOffset.x < -20) ) {
// go to next item
itemsDiff = 1;
}
}
And, were going to do something similar to this function as in part one. Change the code to the following:
if(gestureType === 'swipe') {
var totalShiftDist = _currPoint.x - _startPoint.x,
isFastLastFlick = _releaseAnimData.lastFlickDist.x < 10;
// if container is shifted for more than MIN_SWIPE_DISTANCE,
// and last flick gesture was in right direction
if(totalShiftDist > MIN_SWIPE_DISTANCE &&
(isFastLastFlick || _releaseAnimData.lastFlickOffset.x > 20) ) {
// go to prev item
if ( (_currentItemIndex + 1) === 1) {
self.close();
} else {
itemsDiff = -1;
}
} else if(totalShiftDist < -MIN_SWIPE_DISTANCE &&
(isFastLastFlick || _releaseAnimData.lastFlickOffset.x < -20) ) {
// go to next item
if ( (_currentItemIndex + 1) === _getNumItems() ) {
self.close();
} else {
itemsDiff = 1;
}
}
}
I have tested on my site and it works correctly.
Enjoy :)

Bootstrap slider - prevent flipping the two cursors and stop slide

I would like to use Bootstrap slider to represent 3 lengths of axes whose sum doesn't change (the max value of the slider corresponds to this sum).
So I have 2 cursors on bootstrap slider and the 3 intervals represent these lengths.
Here's an example: bootstrap with two cursors
My issue is that I would like to stop dragging the second cursor (on the right) when it is equal (or nearly with a fixed step) to the first one (on the left) and inversely for the first cursor.
I saw there's an slide stop event but this doesn't seem to be the same thing.
I have surely to modify the bootstrap-slider.js source but I don't know how to do for implementing this specific functionality.
It would be like:
slider.on("slide", function(slideEvt) {
if ((cursor2.value - cursor1.value) < step)
{ this.stopSlide();}
});
Using slides events it's possible. The idea is to see which cursor is fixed, and when its value change, block the slide movement, by setting value.
Didn't find a cleaner way to block slide event...
Working code :
var slider = new Slider("#slider1");
var initPos,
fixedCursor,
fixedCursorPos;
slider.on("slideStart", function(slideEvt) {
initPos = slideEvt;
fixedCursor = null;
fixedCursorPos = null;
});
slider.on("slide", function(slideEvt) {
if (initPos[0] !== initPos[1] && (slideEvt[0] !== initPos[0] || slideEvt[1] !== initPos[1])) {
if (fixedCursor == null) {
fixedCursor = (slideEvt[0] === initPos[0] ? 0 : 1);
fixedCursorPos = slideEvt[fixedCursor];
}
if (fixedCursorPos !== slideEvt[fixedCursor]) {
slider.setValue([fixedCursorPos, fixedCursorPos], false, false);
}
}
});
Working JS Bin : http://jsbin.com/kopakiciti/1/edit?html,js,output

How to reinitialise jScrollPane without losing features added in the first initialisation?

I'm having trouble with jScrollPane's reinitialise() method. Whenever I call it, stuff that I implemented in the first initialisation stops working...
In my current code, I'm doing something like this:
$('.scrollable').each(function(){
var e = $(this),
parent = e.parent();
e.jScrollPane({
// parameters
});
var api = e.data('jsp'),
arrowup = e.find('.jspArrowUp'),
arrowdw = e.find('.jspArrowDown');
if ( api.getIsScrollableV() ) {
e.addClass('scrolled-top');
parent.addClass('scroll-parent');
}
e.scroll(function(){
var scrbef = api.getContentPositionY(),
scrmax = api.getContentHeight() - this.clientHeight,
scraft = scrmax - scrbef,
dlayup = (scrbef - 220)/100,
dlaydw = (scraft - 220)/100,
opacup = dlayup > 1 ? 1 : dlayup < 0 ? 0 : dlayup,
opacdw = dlaydw > 1 ? 1 : dlaydw < 0 ? 0 : dlaydw;
if ( scrbef === 0 ) {
e.addClass('scrolled-top').removeClass('scrolled-bot');
} else if ( scraft === 0 ) {
e.addClass('scrolled-bot').removeClass('scrolled-top');
} else {
e.removeClass('scrolled-top scrolled-bot');
}
arrowup.css('opacity', opacup);
arrowdw.css('opacity', opacdw);
});
So far, so good. What that does is:
initialise jScrollPane on the .scrollable elements
depending on the content position, add or remove scrolled-top or scrolled-bot classes.
controls the opacity of the arrows depending on the content's position (there's a lot of padding at the top and bottom, so I only want the arrows to appear when the actual content has reached the border of the screen).
Right after that bit, I have this:
var throttleTimeout;
$(window).resize(function(){
if ( !throttleTimeout ) {
throttleTimeout = setTimeout( function(){
api.reinitialise();
throttleTimeout = null;
}, 500
);
}
});
$('.deployer').click(function(e){
api.reinitialise();
});
});
Now, that is pretty straightforward; the code to reinitialise when the window is resized comes straight from the documentation.
However, as soon as either reinitialise() is called, so after resizing the window or clicking on the .deployer element, the previous code which controlled the arrows' opacity stops working – although, weirdly enough, the scrolled-top and scrolled-bot classes still get added or removed properly.
Does anyone know what might be causing this behaviour and how to fix it?
Cheers.
Found what was happening.
Whenever you reinitialise, basically everything gets resetted, so the elements that were previously stored in arrowup and arrowdw don't exist anymore. Adding
var arrowup = e.find('.jspArrowUp'),
arrowdw = e.find('.jspArrowDown');
again after each reinitialise() made the trick.

How to find exact draggable grid line position in rulerguides.js?

I am currently working in rulerguides.js. And i customized into particular div for rulers and grid line.REFER THIS FIDDLE. Rulers are working fine for me but drag-gable create div (GRID LINES) calculated from body element only , that means top of window and left edges of window.Here In my code i can send particular div for rulers
var evt = new Event(),
dragdrop = new Dragdrop(evt),
rg = new RulersGuides(evt, dragdrop,document.getElementById('workarea'));
I need to start from particular div
(For example : ruler h unselectable class will create horizontal grid line and ruler v unselectable class will create vertical grid line in my working area.)
How to get draggable starting element ? And i need to start in particular div just like image
.
I am struggle for more than 2 days.How to solve this issues?
Actually RulersGuides.js is not intended to be used in containers other than document body, so I would think about placing it in an iframe.
If you really need to have it a in a div, here are some adjustments needed:
Update getWindowSize, getScrollPos and getScrollSize functions to calculate container dimensions.
Instead of using vBound and hBound in mousedown handler you need to introduce vLowBound, vHighBound, etc., where container's left and top offsets will be taken in account, like this:
if (vLowBound === 0) {
vLowBound = container.offsetLeft;
vHighBound = vRuler.offsetWidth + vLowBound;
hLowBound = container.offsetTop;
hHighBound = hRuler.offsetHeight + hLowBound;
}
with appropriate checks
if (
(
(x > vLowBound && x < vHighBound) ||
(y > hLowBound && y < hHighBound)
) && rulerStatus === 1
)
and then
if (y > hLowBound && y < hHighBound) {
and
} else if (x > vLowBound && x < vHighBound) {
accordingly
Update removeInboundGuide accordingly in the same way.
Other than that, I think there'll be needed some changes in dom dimensions calculations, dialogs etc.
Please refer to the following jsfiddle for the details.

Check if object is within css border/ css wrapper

I would like to begin with saying i am new to the whole programming scene. This is my first jQuery project for ICT at school.
The project:
I have multiple draggable objects (images). They are in #wrapper, wrapper is in my style.css
Now i want to make it so that when the images are dragged over a background image (centered), located under the wrapper, they will change from image. I have done this successfully by getting the location of each object:
drag: function(){
var who = $("#draggable1");
var offset1 = who.offset();
var xPos1 = offset1.left;
var yPos1 = offset1.top;
$('#posX').text('x: ' + xPos1);
$('#posY').text('y: ' + yPos1);
Then check where the object is, and if its within the X and Y of my background picture, they change:
if(yPos1 > '115' && yPos1 < '578')
{
this.src = 'pinkward5.png'
}
And also code if the object is dropped outside of the background image, this will make it go back to its original place:
if(xPos1 < '717' || xPos1 > '1202')
{
who.animate({ 'top': offset1.top == '0', 'left': offset1.left == '0'}, 200, function(){
who.stop( true,true );
who.mouseup();
this.src = 'visionward.png'
});
BUT:
If i use another monitor with another resolution or leave the browser on the half of my screen, the coordinates change, and the code doenst work as it should because the offset changes.
My question:
How can i make that no matter what the resolution or window of the browser, the coordinates are the same. Maybe with percentages or check if the object is within the css border of the background image?
Thanks! i hope i have not violated the stackoverflow rules.
Why to hardcode the coordinates?
Simply call "offset()" on the background image to get the coordinates, exactly like what you did on the draggable element, and calculate the bounds with its width and height.
var bkgd = $('.whatever-you-name-the-background-image-class');
var bkgd_offset = bkgd.offset();
if(xPos1 >= bkgd_offset.left && xPos1 + who.width() <= bkgd_offset.left + bkgd.width() &&
yPos1 >= bkgd_offset.top && yPos1 + who.height() <= bkgd_offset.top + bkgd.height())
/* draggable inside background */;
else
/* not inside background */;

Categories

Resources