Embla Carousel - select inner text - javascript

I have a carousel built using Embla Carousel (embla-carousel-react).
The elements within the carousel contain an image and some text. The text is not selectable, but I would like it to be.
When I set draggable: false, I can select the text inside the carousel, but now I can no longer scroll the carousel to the next slide.
Is there a way I can have both - select and copy text with a mouse click and drag, and swipe to the next scroll with a more pronounced swipe or scroll gesture?
const EmblaCarousel = ({ children, nextScroll, recordCurrentSlide }) => {
const { height } = useWindowDimensions()
const [viewportRef, embla] = useEmblaCarousel({
axis: "y",
skipSnaps: false,
startIndex: 0,
draggable: true,
dragFree: false,
slidesToScroll: 1,
loop: true,
},
[WheelGesturesPlugin()]);
return (
<div className="embla">
<div className="embla__viewport" ref={viewportRef}>
<div className="embla__container">
{children}
</div>
</div>
<style jsx>{`
:global(.embla__container) {
height: ${height};
}
`}</style>
</div>
);
};
Thanks!

I'm the creator of Embla Carousel and at the time of writing, what you want to achieve isn't possible. This is because Embla calls event.preventDefault() on touch and mouse events when the carousel has draggable: true set.
If you want to discuss this design choice and suggest changes, you may create a new discussion.

Related

React : SortableJS: Exclude some last elements from sorting

I have a list something similar to this in React
<div id="list">
<Item data-id="1">
<Item data-id="2">
<Item data-id="3">
<Item data-id="4">
<Item data-id="5">
</div>
I am using sortablejs npm library for sorting.
Now, I want to exclude the last 2 elements from sorting,
Below is the function I use for sorting
import Sortable from 'sortablejs';
let list = document.getElementById('list');
Sortable.create(list, {
ghostClass: 'ghost',
store : {
set: (sortable) => {
// logic to store new order in DB
sortable.destroy();
}
}
});
Expected Result:
Last 2 items should become non-draggable
also, first 3 items should not be able to go below them
How can I achieve that?
Solution for a similar problem is at:
How to exclude an element from being dragged in sortable list?
I want equivalent of below mentioned code in React:
$(function() {
$('.sortable').sortable();
$('.sortable').disableSelection();
$('.sortable').sortable({ cancel: '.note' });
});​
$('.sortable').sortable({
items : ':not(.note)'
});
maybe you can use the "filter" config option?
var sortable = new Sortable(el, {
// variables
group: "name", // or { name: "...", pull: [true, false, 'clone', array], put: [true, false, array] }
sort: true, // sorting inside list
delay: 0, // time in milliseconds to define when the sorting should start
delayOnTouchOnly: false, // only delay if user is using touch
touchStartThreshold: 0, // px, how many pixels the point should move before cancelling a delayed drag event
disabled: false, // Disables the sortable if set to true.
store: null, // #see Store
animation: 150, // ms, animation speed moving items when sorting, `0` — without animation
easing: "cubic-bezier(1, 0, 0, 1)", // Easing for animation. Defaults to null. See https://easings.net/ for examples.
handle: ".my-handle", // Drag handle selector within list items
filter: ".ignore-elements", // Selectors that do not lead to dragging (String or Function)
preventOnFilter: true, // Call `event.preventDefault()` when triggered `filter`
draggable: ".item", // Specifies which items inside the element should be draggable
dataIdAttr: "data-id",
ghostClass: "sortable-ghost", // Class name for the drop placeholder
chosenClass: "sortable-chosen", // Class name for the chosen item
dragClass: "sortable-drag", // Class name for the dragging item
swapThreshold: 1, // Threshold of the swap zone
invertSwap: false, // Will always use inverted swap zone if set to true
invertedSwapThreshold: 1, // Threshold of the inverted swap zone (will be set to swapThreshold value by default)
direction: "horizontal", // Direction of Sortable (will be detected automatically if not given)
forceFallback: false, // ignore the HTML5 DnD behaviour and force the fallback to kick in
fallbackClass: "sortable-fallback", // Class name for the cloned DOM Element when using forceFallback
fallbackOnBody: false, // Appends the cloned DOM Element into the Document's Body
fallbackTolerance: 0, // Specify in pixels how far the mouse should move before it's considered as a drag.
dragoverBubble: false,
removeCloneOnHide: true, // Remove the clone element when it is not showing, rather than just hiding it
emptyInsertThreshold: 5, // px, distance mouse must be from empty sortable to insert drag element into it

Openseadragon : weird selection rotation when rotating canvas

I am currently working on a viewer using OpenSeadragon, and the Picturae selection plugin for adding a cropping tool.
Selection is working fine, but when I rotate the image, rotation of selection is acting weird : it rotate around the bottom left corner, instead of the center of selection.
I made a video of the case : normal behavior of selection rotation when image is straight, and weird behavior when image is rotated.
The desired effect is to rotate around the center of selection...
I use the following code to initialize selection :
var selection = viewer.selection({
element: null, // html element to use for overlay
showSelectionControl: true, // show button to toggle selection mode
toggleButton: null, // dom element to use as toggle button
showConfirmDenyButtons: true,
styleConfirmDenyButtons: true,
returnPixelCoordinates: true,
keyboardShortcut: 'c', // key to toggle selection mode
rect: null, // initial selection as an OpenSeadragon.SelectionRect object
startRotated: false, // alternative method for drawing the selection; useful for rotated crops
startRotatedHeight: 0.1, // only used if startRotated=true; value is relative to image height
restrictToImage: true, // true = do not allow any part of the selection to be outside the image
onSelection: function(rect) { viewer_crop_download(rect); },
cancel : function(){ viewer_crop_disable(); },
prefixUrl: PREFIX_URL,
navImages:
{
selection: {
REST: 'selection_rest.png',
GROUP: 'selection_grouphover.png',
HOVER: 'selection_hover.png',
DOWN: 'selection_pressed.png'
},
selectionConfirm: {
REST: 'selection_confirm_rest.png',
GROUP: 'selection_confirm_grouphover.png',
HOVER: 'selection_confirm_hover.png',
DOWN: 'selection_confirm_pressed.png'
},
selectionCancel: {
REST: 'selection_cancel_rest.png',
GROUP: 'selection_cancel_grouphover.png',
HOVER: 'selection_cancel_hover.png',
DOWN: 'selection_cancel_pressed.png'
},
}
});
OpenSeadragon : https://openseadragon.github.io
Picturae selection plugin : https://picturae.github.io/openseadragonselection/
Thanks !

jQuery Scrollify - first section ignores offset

First time using jquery-scrollify. I have a page with a border around it and each section is meant to start 24px from top of page so it starts below the border. Without scrollify my CSS does this fine. Once I implement scrollify, even with the correct offset option, the page is always scrolled so that the top of this first section is right at the top of the page. Once I start scrolling to lower sections, they are respecting the offset and aligning properly. It seems the offset options is ignored for the first section? Is there any way to make the offset apply to the first section / start of page?
HTML
<section class="hero-home">
<div class="slide" style="background-image: url('/img/hero-home1.jpg')"></div>
<div class="slide" style="background-image: url('/img/hero-home2.jpg')"></div>
<div class="slide" style="background-image: url('/img/hero-home3.jpg')"></div>
<div class="slide" style="background-image: url('/img/hero-home4.jpg')"></div>
</section>
JS
var scrollOffset = -24;
$.scrollify({
section: ".slide:visible",
offset: scrollOffset,
easing: "easeOutQuint",
scrollSpeed: 800,
scrollbars: true,
setHeights: false,
updateHash: false,
touchScroll: true
});
The -24 offset is to account for a fixed position frame I have at top of the page. When a new "section" is scrolled to the top, it should stop 24px from top of page rather than right at the top, otherwise it goes under the frame.
The first "section" starts in the right place before I initiate scrollify (my CSS on a containing element has top padding equal to height of the frame). However once scrollify is added, the page is scrolled down 24px so that the first "section" appears right at the top of page. The "offset" options corrects this on all subsequent sections (2nd, 3rd, and 4th section appear at the right place when I scroll down) but the 1st section's initial position is incorrect and ignores the offset option value.
I struggled with this issue as well, to fix this issue you want to provide some handling in the before event.
Solution Example
$(document).ready(function() {
$.scrollify({
section : ".fp-section",
offset:-200,
setHeights:false,
//Add the offset for the first element here:
//snapToElm is the list of element pages
before:function(indexPosition,snapToElm){
if(indexPosition===0){
snapToElm[0].css({"margin-top":"200px"});
}
if(indexPosition>0){
snapToElm[0].css({"margin-top":"0"});
}
},
afterRender:function(){
//set the first element initially to the desired offset
$($(this.section)[0]).css({"margin-top":"200px"});
// stuff to do once scrollify has rendered the list
}
})
});
$.scrollify({
section: "section",
interstitialSection: ".fourth-view,footer",
easing: "easeOutExpo",
scrollSpeed: 1100,
offset:0,
scrollbars: true,
standardScrollElements: "",
setHeights: false,
overflowScroll: true,
updateHash: false,
touchScroll: true,
before: function () {
},
after: function () {
},
afterResize: function () {
},
afterRender: function () {
}
});
if ($.scrollify.current().hasClass('second-view')) {
$.scrollify.setOptions({offset: 0})
}
else {
$.scrollify.setOptions({offset: -64.5})
}
and also
$(window).on('scroll', function () {
if ($.scrollify.current().hasClass('second-view')) {
$.scrollify.setOptions({offset: 0})
}
else {
$.scrollify.setOptions({offset: -64.5})
}
});
remove offset for second section
Change the source code line 660 of jquery.scrollify.js
if(i>0) {
heights[i] = parseInt($this.offset().top) + settings.offset;
} else {
heights[i] = parseInt($this.offset().top);
}
Change to
heights[i] = parseInt($this.offset().top) + settings.offset;
The version of jQuery Scrollify is 1.0.20
I tried the solution below but finally I just added the "section / slide class" to my header or navbar (<header class="slide navbar otherclasses..."></header>) that make my navbar the first element, it may not fit anyone but in my case its by far the most confortable for my users.
Edit : you need to set setHeights: false otherwise its not going to work well.

Only use scroll-snap on specific sections, otherwise use normal scroll

First of all I want to say that I really like Scrollify and I am now planning to use it. The idea for my site is to have some sections that have snap scrolling behavior and some sections with normal scrolling. Everything works fine EXCEPT that I don't want it to do snap scroll when going from a snap section to a normal section. As it is now it snap scrolls to the normal section and first after it has snapped it goes to normal scrolling.
In other words I think what I am looking for is to be able to control when snap-scrolling is enabled depending on the element that is in the viewport. Maybe there is an easier solution though.
Do you have any suggestions?
(function() {
var firstSection = $('.wrapper .normal-page').eq(0)[0]
var firstSectionClassName = $(firstSection).attr('class')
var base = this;
$.scrollify({
section : ".product-page",
sectionName : "section-name",
interstitialSection : ".normal-page",
easing: "easeOutExpo",
scrollSpeed: 1100,
offset : 0,
scrollbars: true,
standardScrollElements: ".normal-page",
setHeights: true,
overflowScroll: true,
before:function(index, arr) {
var currentItem = $.scrollify.current().attr('class')
if (currentItem !== "product-page") {
$.scrollify.disable();
}
},
after:function() {
$.scrollify.enable();
},
afterResize:function() {
},
afterRender:function() {
console.log("move to the top")
$.scrollify.instantMove("#" + firstSectionClassName)
}
});
})()
HTML
<body>
<div class="wrapper">
<div class="normal-page"></div>
<div class="product-page"></div>
<div class="normal-page"></div>
<div class="product-page"></div>
<div class="normal-page"></div>
</div>
</body>
so I am already trying with the enable and disable methods, but
You'll probably need to use the disable and enable methods to achieve this.

carouFredSel: Show partial items?

I'm using carouFredSel to create a vertical carousel. Everything works great, except I would prefer if partial items would be shown at the bottom, cropped, rather than being hidden. This way it would indicate to users that there are additional items that can be scrolled.
I have been reading the documentation, but so far can't tell if what I am after is possible.
Check out the JSFiddle to see what I mean. Watch the bottom most item on the page.
Javascript
$("ul").carouFredSel({
direction: "up",
align: "top",
width: 100,
height: "100%",
items: {
visible: "variable",
width: 100,
height: "variable"
},
scroll: {
items: 1,
mousewheel: true,
easing: "swing",
duration: 500
},
auto: false,
prev: {
button: ".prev",
key: "up"
},
next: {
button: ".next",
key: "down"
}
});​
This is a bit of a hack, but it works. Set the height of the scroller (in this case, ul) to 150% and the parent element (in this case, body) to overflow: hidden. Now the bottom most element is off screen.
Javascript
$("ul").carouFredSel({
height: "150%"
});
CSS
body {
overflow: hidden;
}
Ha, caroufredsel supports it, no hacks required :))! You can achieve it with the following option:
items: {
visible: '+1'
}
EDIT: This suffers from a problem though. If number of whole visible items + 1 == number of all items, then carousel cannot be scrolled even though one image is visible just partially. You can overcome this issue by setting e.g. minimum: 1 but it is not always a way to go (e.g. if number of images is dynamic and you don't want scroll handlers to appear when there is just one or two images.).
The next not visible element in the vertical carousel is pushed down by the margin.
I'm currently overriding it by the following function:
function cropCarousel () {
var visibleElements = this.triggerHandler("currentVisible"), // show all visible
$lastElement = $(visibleElements[visibleElements.length - 1]); // get the last one
$lastElement.css('margin-bottom', '30px'); // amend the margin
};
cropCarousel.call($('#your_carousel_id'));
The downside of it that you will have to call this function on carousel init and on up and down events. But it works ;)

Categories