vue-carousel-3d
Version:
Beautiful, flexible and touch supported 3D Carousel for Vue.js
867 lines (866 loc) • 30.9 kB
JavaScript
(function() {
//#region \0vite/all-css
try {
if (typeof document != "undefined") {
var elementStyle = document.createElement("style");
elementStyle.appendChild(document.createTextNode(".carousel-3d-slide {\r\n position: absolute;\r\n opacity: 0;\r\n visibility: hidden;\r\n overflow: hidden;\r\n top: 0;\r\n border-radius: 1px;\r\n border-color: #000;\r\n border-color: rgba(0, 0, 0, 0.4);\r\n border-style: solid;\r\n background-size: cover;\r\n background-color: #ccc;\r\n display: block;\r\n margin: 0;\r\n box-sizing: border-box;\n}\n.carousel-3d-slide {\r\n text-align: left;\n}\n.carousel-3d-slide img {\r\n width: 100%;\n}\n.carousel-3d-slide.current {\r\n opacity: 1 !important;\r\n visibility: visible !important;\r\n transform: none !important;\r\n z-index: 999;\n}\r\n\r\n\n.carousel-3d-controls[data-v-35bea2a2] {\r\n position: absolute;\r\n top: 50%;\r\n height: 0;\r\n margin-top: -30px;\r\n left: 0;\r\n width: 100%;\r\n z-index: 1000;\n}\n.next[data-v-35bea2a2], .prev[data-v-35bea2a2] {\r\n padding: 0;\r\n border: 0;\r\n background: transparent;\r\n width: 60px;\r\n position: absolute;\r\n z-index: 1010;\r\n font-size: 60px;\r\n height: 60px;\r\n line-height: 60px;\r\n color: #333;\r\n -webkit-user-select: none;\r\n -moz-user-select: none;\r\n -ms-user-select: none;\r\n user-select: none;\r\n text-decoration: none;\r\n top: 0;\n}\n.next[data-v-35bea2a2]:hover, .prev[data-v-35bea2a2]:hover {\r\n cursor: pointer;\r\n opacity: 0.7;\n}\n.prev[data-v-35bea2a2] {\r\n left: 10px;\r\n text-align: left;\n}\n.next[data-v-35bea2a2] {\r\n right: 10px;\r\n text-align: right;\n}\n.disabled[data-v-35bea2a2] {\r\n opacity: 0.2;\r\n cursor: default;\n}\n.disabled[data-v-35bea2a2]:hover {\r\n cursor: default;\r\n opacity: 0.2;\n}\r\n\n.carousel-3d-dots[data-v-e1ffb936] {\r\n position: absolute;\r\n left: 0;\r\n width: 100%;\r\n display: flex;\r\n justify-content: center;\r\n gap: 8px;\r\n z-index: 900;\r\n pointer-events: none;\n}\n.carousel-3d-dots--bottom[data-v-e1ffb936] {\r\n bottom: 14px;\n}\n.carousel-3d-dots--top[data-v-e1ffb936] {\r\n top: 14px;\n}\n.carousel-3d-dot[data-v-e1ffb936] {\r\n pointer-events: auto;\r\n width: 10px;\r\n height: 10px;\r\n padding: 0;\r\n border: 0;\r\n border-radius: 50%;\r\n background: rgba(0, 0, 0, 0.35);\r\n cursor: pointer;\r\n transition: background-color 200ms ease;\n}\n.carousel-3d-dot[data-v-e1ffb936]:hover {\r\n background: rgba(0, 0, 0, 0.55);\n}\n.carousel-3d-dot.is-active[data-v-e1ffb936] {\r\n background: rgba(0, 0, 0, 0.85);\n}\r\n\n.carousel-3d-container[data-v-db4a8480] {\r\n min-height: 1px;\r\n width: 100%;\r\n position: relative;\r\n z-index: 0;\r\n overflow: hidden;\r\n touch-action: pan-y;\r\n margin: 20px auto;\r\n box-sizing: border-box;\n}\n.carousel-3d-slider[data-v-db4a8480] {\r\n position: relative;\r\n margin: 0 auto;\r\n transform-style: preserve-3d;\r\n -webkit-perspective: 1000px;\r\n -moz-perspective: 1000px;\r\n perspective: 1000px;\n}\r\n\r\n/*$vite$:1*/"));
document.head.appendChild(elementStyle);
}
} catch (e) {
console.error("vite-plugin-css-injected-by-js", e);
}
//#endregion
})();
(function(global, factory) {
typeof exports === "object" && typeof module !== "undefined" ? factory(exports, require("vue")) : typeof define === "function" && define.amd ? define(["exports", "vue"], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global["carousel-3d"] = {}, global.Vue));
})(this, function(exports, vue) {
Object.defineProperties(exports, {
__esModule: { value: true },
[Symbol.toStringTag]: { value: "Module" }
});
//#region \0plugin-vue:export-helper
var _plugin_vue_export_helper_default = (sfc, props) => {
const target = sfc.__vccOpts || sfc;
for (const [key, val] of props) target[key] = val;
return target;
};
//#endregion
//#region src/carousel-3d/Slide.vue
var _sfc_main$3 = {
name: "slide",
props: { index: { type: Number } },
inject: ["carousel"],
data() {
return {
styles: {},
zIndex: 999
};
},
computed: {
parent() {
return this.carousel;
},
isCurrent() {
return this.index === this.parent.currentIndex;
},
shouldRenderContent() {
if (!this.parent.lazy) return true;
const distance = Math.abs(this.index - this.parent.currentIndex);
return Math.min(distance, this.parent.total - distance) <= Math.max(this.parent.visible + 1, 3);
},
slideAriaLabel() {
return Number.isInteger(this.index) ? `${this.index + 1} of ${this.parent.total}` : void 0;
},
leftIndex() {
if (this.parent.oneDirectional && this.getSideIndex(this.parent.leftIndices) > this.parent.currentIndex - 1) return -1;
return this.getSideIndex(this.parent.leftIndices);
},
rightIndex() {
if (this.parent.oneDirectional && this.getSideIndex(this.parent.rightIndices) > this.parent.total - this.parent.currentIndex - 2) return -1;
return this.getSideIndex(this.parent.rightIndices);
},
slideStyle() {
let styles = {};
if (!this.isCurrent) {
const lIndex = this.leftIndex;
const rIndex = this.rightIndex;
if (rIndex >= 0 || lIndex >= 0) {
styles = rIndex >= 0 ? this.calculatePosition(rIndex, true, this.zIndex) : this.calculatePosition(lIndex, false, this.zIndex);
styles.opacity = 1;
styles.visibility = "visible";
}
if (this.parent.hasHiddenSlides) {
if (this.matchIndex(this.parent.leftOutIndex)) styles = this.calculatePosition(this.parent.leftIndices.length - 1, false, this.zIndex);
else if (this.matchIndex(this.parent.rightOutIndex)) styles = this.calculatePosition(this.parent.rightIndices.length - 1, true, this.zIndex);
}
}
return Object.assign(styles, {
"border-width": this.parent.border + "px",
"width": this.parent.slideWidth + "px",
"height": this.parent.slideHeight + "px",
"transition": " transform " + this.parent.animationSpeed + "ms, opacity " + this.parent.animationSpeed + "ms, visibility " + this.parent.animationSpeed + "ms"
});
},
computedClasses() {
return {
[`left-${this.leftIndex + 1}`]: this.leftIndex >= 0,
[`right-${this.rightIndex + 1}`]: this.rightIndex >= 0,
"current": this.isCurrent
};
}
},
methods: {
getSideIndex(array) {
let index = -1;
array.forEach((pos, i) => {
if (this.matchIndex(pos)) index = i;
});
return index;
},
matchIndex(index) {
return index >= 0 ? this.index === index : this.parent.total + index === this.index;
},
calculatePosition(i, positive, zIndex) {
const z = !this.parent.disable3d ? parseInt(this.parent.inverseScaling) + (i + 1) * 100 : 0;
const y = !this.parent.disable3d ? parseInt(this.parent.perspective) : 0;
const leftRemain = this.parent.space === "auto" ? parseInt((i + 1) * (this.parent.width / 1.5), 10) : parseInt((i + 1) * this.parent.space, 10);
const horizon = this.parent.horizonOffset ? parseInt(this.parent.horizonOffset, 10) * (i + 1) : 0;
return {
transform: positive ? "translateX(" + leftRemain + "px) translateZ(-" + z + "px) rotateY(-" + y + "deg)" + (horizon ? " translateY(" + horizon + "px)" : "") : "translateX(-" + leftRemain + "px) translateZ(-" + z + "px) rotateY(" + y + "deg)" + (horizon ? " translateY(" + horizon + "px)" : ""),
top: this.parent.space === "auto" ? 0 : parseInt((i + 1) * this.parent.space),
zIndex: zIndex - (Math.abs(i) + 1)
};
},
goTo() {
if (!this.isCurrent) {
if (this.parent.clickable === true) this.parent.goFar(this.index);
} else {
const { index } = this;
this.parent.onMainSlideClick({ index });
}
}
}
};
var _hoisted_1$3 = ["aria-hidden", "aria-label"];
function _sfc_render$3(_ctx, _cache, $props, $setup, $data, $options) {
return (0, vue.openBlock)(), (0, vue.createElementBlock)("div", {
class: (0, vue.normalizeClass)(["carousel-3d-slide", $options.computedClasses]),
style: (0, vue.normalizeStyle)($options.slideStyle),
onClick: _cache[0] || (_cache[0] = ($event) => $options.goTo()),
role: "group",
"aria-roledescription": "slide",
"aria-hidden": String(!$options.isCurrent),
"aria-label": $options.slideAriaLabel
}, [$options.shouldRenderContent ? (0, vue.renderSlot)(_ctx.$slots, "default", {
index: $props.index,
isCurrent: $options.isCurrent,
leftIndex: $options.leftIndex,
rightIndex: $options.rightIndex
}, void 0, void 0, 0) : (0, vue.createCommentVNode)("", true)], 14, _hoisted_1$3);
}
var Slide_default = /*#__PURE__*/ _plugin_vue_export_helper_default(_sfc_main$3, [["render", _sfc_render$3]]);
//#endregion
//#region src/carousel-3d/core/carousel.js
function getVisibleSlideCount(display, total) {
return display > total ? total : display;
}
function getSideIndices({ currentIndex, total, visible, bias, dir, side }) {
let count = (visible - 1) / 2;
const isLeft = side === "left";
count = bias.toLowerCase() === side ? Math.ceil(count) : Math.floor(count);
const indices = [];
for (let position = 1; position <= count; position++) {
const movesForward = isLeft && dir === "ltr" || !isLeft && dir !== "ltr";
indices.push(movesForward ? (currentIndex + position) % total : (currentIndex - position) % total);
}
return indices;
}
function getOutIndex({ currentIndex, total, visible, bias, dir, side }) {
const isLeft = side === "left";
let offset = (visible - 1) / 2;
offset = (bias.toLowerCase() === side ? Math.ceil(offset) : Math.floor(offset)) + 1;
if (isLeft && dir === "ltr" || !isLeft && dir !== "ltr") return total - currentIndex - offset <= 0 ? -parseInt(total - currentIndex - offset, 10) : currentIndex + offset;
return currentIndex - offset;
}
function getSafeIndex(index, total) {
const targetIndex = parseInt(index, 10);
return !Number.isFinite(targetIndex) || targetIndex < 0 || targetIndex >= total ? 0 : targetIndex;
}
function getStartIndex(index, total) {
if (total === 0) return 0;
const startIndex = Math.max(0, parseInt(index, 10) || 0);
return startIndex > total - 1 ? total - 1 : startIndex;
}
//#endregion
//#region src/carousel-3d/mixins/autoplay.js
var isBrowser$1 = typeof window !== "undefined";
var autoplay = {
props: {
autoplay: {
type: Boolean,
default: false
},
autoplayTimeout: {
type: Number,
default: 2e3
},
autoplayHoverPause: {
type: Boolean,
default: true
}
},
data() {
return { autoplayInterval: null };
},
mounted() {
if (!isBrowser$1) return;
if (this.autoplayHoverPause) {
this.$el.addEventListener("mouseenter", this.pauseAutoplay);
this.$el.addEventListener("mouseleave", this.startAutoplay);
}
this.startAutoplay();
},
beforeUnmount() {
if (!isBrowser$1) return;
this.pauseAutoplay();
if (this.autoplayHoverPause) {
this.$el.removeEventListener("mouseenter", this.pauseAutoplay);
this.$el.removeEventListener("mouseleave", this.startAutoplay);
}
},
methods: {
pauseAutoplay() {
if (this.autoplayInterval) {
clearInterval(this.autoplayInterval);
this.autoplayInterval = null;
}
},
startAutoplay() {
this.pauseAutoplay();
if (this.autoplay) this.autoplayInterval = setInterval(() => {
this.dir === "ltr" ? this.goPrev() : this.goNext();
}, this.autoplayTimeout);
}
}
};
//#endregion
//#region src/carousel-3d/Controls.vue
var _sfc_main$2 = {
name: "controls",
props: {
/**
* Width in pixels of the navigation buttons
*/
width: {
type: [String, Number],
default: 50
},
/**
* Height in pixels of the navigation buttons
*/
height: {
type: [String, Number],
default: 60
},
/**
* Text content of the navigation prev button
*/
prevHtml: {
type: String,
default: "‹"
},
/**
* Text content of the navigation next button
*/
nextHtml: {
type: String,
default: "›"
}
},
inject: ["carousel"],
computed: { parent() {
return this.carousel;
} }
};
var _hoisted_1$2 = { class: "carousel-3d-controls" };
var _hoisted_2$1 = ["disabled"];
var _hoisted_3 = ["innerHTML"];
var _hoisted_4 = ["disabled"];
var _hoisted_5 = ["innerHTML"];
function _sfc_render$2(_ctx, _cache, $props, $setup, $data, $options) {
return (0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_1$2, [(0, vue.createElementVNode)("button", {
type: "button",
class: (0, vue.normalizeClass)(["prev", { disabled: !$options.parent.isPrevPossible }]),
onClick: _cache[0] || (_cache[0] = ($event) => $options.parent.goPrev()),
disabled: !$options.parent.isPrevPossible,
style: (0, vue.normalizeStyle)(`width: ${$props.width}px; height: ${$props.height}px; line-height: ${$props.height}px;`),
"aria-label": "Previous slide"
}, [(0, vue.renderSlot)(_ctx.$slots, "prev", {
goPrev: $options.parent.goPrev,
disabled: !$options.parent.isPrevPossible
}, () => [(0, vue.createElementVNode)("span", { innerHTML: $props.prevHtml }, null, 8, _hoisted_3)], true)], 14, _hoisted_2$1), (0, vue.createElementVNode)("button", {
type: "button",
class: (0, vue.normalizeClass)(["next", { disabled: !$options.parent.isNextPossible }]),
onClick: _cache[1] || (_cache[1] = ($event) => $options.parent.goNext()),
disabled: !$options.parent.isNextPossible,
style: (0, vue.normalizeStyle)(`width: ${$props.width}px; height: ${$props.height}px; line-height: ${$props.height}px;`),
"aria-label": "Next slide"
}, [(0, vue.renderSlot)(_ctx.$slots, "next", {
goNext: $options.parent.goNext,
disabled: !$options.parent.isNextPossible
}, () => [(0, vue.createElementVNode)("span", { innerHTML: $props.nextHtml }, null, 8, _hoisted_5)], true)], 14, _hoisted_4)]);
}
var Controls_default = /*#__PURE__*/ _plugin_vue_export_helper_default(_sfc_main$2, [["render", _sfc_render$2], ["__scopeId", "data-v-35bea2a2"]]);
//#endregion
//#region src/carousel-3d/Dots.vue
var _sfc_main$1 = {
name: "carousel-3d-dots",
props: { position: {
type: String,
default: "bottom"
} },
inject: ["carousel"],
computed: {
parent() {
return this.carousel;
},
total() {
return this.parent.total;
},
currentIndex() {
return this.parent.currentIndex;
}
}
};
var _hoisted_1$1 = ["aria-label"];
var _hoisted_2 = [
"aria-label",
"aria-current",
"onClick"
];
function _sfc_render$1(_ctx, _cache, $props, $setup, $data, $options) {
return (0, vue.openBlock)(), (0, vue.createElementBlock)("div", {
class: (0, vue.normalizeClass)(["carousel-3d-dots", `carousel-3d-dots--${$props.position}`]),
role: "group",
"aria-label": `Slide navigation (${$options.total} slides)`
}, [((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)($options.total, (i) => {
return (0, vue.openBlock)(), (0, vue.createElementBlock)("button", {
key: i,
type: "button",
class: (0, vue.normalizeClass)(["carousel-3d-dot", { "is-active": i - 1 === $options.currentIndex }]),
"aria-label": `Go to slide ${i} of ${$options.total}`,
"aria-current": i - 1 === $options.currentIndex ? "true" : void 0,
onClick: ($event) => $options.parent.goSlide(i - 1)
}, null, 10, _hoisted_2);
}), 128))], 10, _hoisted_1$1);
}
var Dots_default = /*#__PURE__*/ _plugin_vue_export_helper_default(_sfc_main$1, [["render", _sfc_render$1], ["__scopeId", "data-v-e1ffb936"]]);
//#endregion
//#region src/carousel-3d/Carousel3d.vue
var isBrowser = typeof window !== "undefined";
var noop = () => {};
function countSlides(nodes) {
return nodes.reduce((count, node) => {
if (node.type === vue.Fragment && Array.isArray(node.children)) return count + countSlides(node.children);
return node.type === vue.Comment || node.type === vue.Text ? count : count + 1;
}, 0);
}
var _sfc_main = {
name: "carousel3d",
components: {
Controls: Controls_default,
Dots: Dots_default
},
emits: [
"after-slide-change",
"before-slide-change",
"last-slide"
],
provide() {
return { carousel: this };
},
props: {
count: {
type: [Number, String],
default: 0
},
perspective: {
type: [Number, String],
default: 35
},
display: {
type: [Number, String],
default: 5
},
loop: {
type: Boolean,
default: true
},
animationSpeed: {
type: [Number, String],
default: 500
},
dir: {
type: String,
default: "rtl"
},
width: {
type: [Number, String],
default: 360
},
height: {
type: [Number, String],
default: 270
},
border: {
type: [Number, String],
default: 1
},
space: {
type: [Number, String],
default: "auto"
},
startIndex: {
type: [Number, String],
default: 0
},
clickable: {
type: Boolean,
default: true
},
disable3d: {
type: Boolean,
default: false
},
minSwipeDistance: {
type: Number,
default: 10
},
inverseScaling: {
type: [Number, String],
default: 300
},
controlsVisible: {
type: Boolean,
default: false
},
controlsPrevHtml: {
type: String,
default: "‹"
},
controlsNextHtml: {
type: String,
default: "›"
},
controlsWidth: {
type: [String, Number],
default: 50
},
controlsHeight: {
type: [String, Number],
default: 50
},
dots: {
type: Boolean,
default: false
},
dotsPosition: {
type: String,
default: "bottom"
},
horizonOffset: {
type: [Number, String],
default: 0
},
lazy: {
type: Boolean,
default: false
},
beforeSlideChange: {
type: Function,
default: noop
},
onLastSlide: {
type: Function,
default: noop
},
onSlideChange: {
type: Function,
default: noop
},
bias: {
type: String,
default: "left"
},
onMainSlideClick: {
type: Function,
default: noop
},
oneDirectional: {
type: Boolean,
default: false
},
ariaLabel: {
type: String,
default: "3D carousel"
}
},
data() {
return {
viewport: 0,
currentIndex: 0,
total: 0,
dragOffsetX: 0,
dragStartX: 0,
dragOffsetY: 0,
dragStartY: 0,
mousedown: false,
zIndex: 998,
animationTimer: null,
navigationTimers: []
};
},
mixins: [autoplay],
watch: { count() {
this.computeData();
} },
created() {
this.computeSlideData(true);
},
computed: {
isLastSlide() {
return this.currentIndex === this.total - 1;
},
isFirstSlide() {
return this.currentIndex === 0;
},
isNextPossible() {
return this.total > 0 && !(!this.loop && this.isLastSlide);
},
isPrevPossible() {
return this.total > 0 && !(!this.loop && this.isFirstSlide);
},
slideWidth() {
const vw = this.viewport;
const sw = parseInt(this.width) + parseInt(this.border, 10) * 2;
return vw > 0 && vw < sw && isBrowser ? vw : sw;
},
slideHeight() {
const sw = parseInt(this.width, 10) + parseInt(this.border, 10) * 2;
const sh = parseInt(parseInt(this.height) + this.border * 2, 10);
const ar = this.calculateAspectRatio(sw, sh);
return this.slideWidth / ar;
},
visible() {
return getVisibleSlideCount(this.display, this.total);
},
hasHiddenSlides() {
return this.total > this.visible;
},
leftIndices() {
return getSideIndices({
currentIndex: this.currentIndex,
total: this.total,
visible: this.visible,
bias: this.bias,
dir: this.dir,
side: "left"
});
},
rightIndices() {
return getSideIndices({
currentIndex: this.currentIndex,
total: this.total,
visible: this.visible,
bias: this.bias,
dir: this.dir,
side: "right"
});
},
leftOutIndex() {
return getOutIndex({
currentIndex: this.currentIndex,
total: this.total,
visible: this.visible,
bias: this.bias,
dir: this.dir,
side: "left"
});
},
rightOutIndex() {
return getOutIndex({
currentIndex: this.currentIndex,
total: this.total,
visible: this.visible,
bias: this.bias,
dir: this.dir,
side: "right"
});
}
},
methods: {
/**
* Go to next slide
*/
goNext() {
if (this.total > 0 && this.isNextPossible) this.isLastSlide ? this.goSlide(0) : this.goSlide(this.currentIndex + 1);
},
/**
* Go to previous slide
*/
goPrev() {
if (this.total > 0 && this.isPrevPossible) this.isFirstSlide ? this.goSlide(this.total - 1) : this.goSlide(this.currentIndex - 1);
},
/**
* Go to slide
* @param {String} index of slide where to go
*/
goSlide(index) {
if (this.total <= 0) return;
const targetIndex = getSafeIndex(index, this.total);
if (this.beforeSlideChange !== noop && this.beforeSlideChange(targetIndex, this.currentIndex) === false) return;
this.currentIndex = targetIndex;
if (this.isLastSlide) {
if (this.onLastSlide !== noop) console.warn("onLastSlide deprecated, please use @last-slide");
this.onLastSlide(this.currentIndex);
this.$emit("last-slide", this.currentIndex);
}
this.$emit("before-slide-change", this.currentIndex);
clearTimeout(this.animationTimer);
this.animationTimer = setTimeout(() => {
this.animationTimer = null;
this.animationEnd();
}, parseInt(this.animationSpeed, 10));
},
/**
* Go to slide far slide
*/
goFar(index) {
this.clearNavigationTimers();
let diff = index === this.total - 1 && this.isFirstSlide ? -1 : index - this.currentIndex;
if (this.isLastSlide && index === 0) diff = 1;
const diff2 = diff < 0 ? -diff : diff;
let timeBuff = 0;
let i = 0;
while (i < diff2) {
i += 1;
const timer = setTimeout(() => {
diff < 0 ? this.goPrev() : this.goNext();
}, diff2 === 1 ? 0 : timeBuff);
this.navigationTimers.push(timer);
timeBuff += this.animationSpeed / diff2;
}
},
clearNavigationTimers() {
this.navigationTimers.forEach((timer) => clearTimeout(timer));
this.navigationTimers = [];
},
/**
* Trigger actions when animation ends
*/
animationEnd() {
if (this.onSlideChange !== noop) console.warn("onSlideChange deprecated, please use @after-slide-change");
this.onSlideChange(this.currentIndex);
this.$emit("after-slide-change", this.currentIndex);
},
/**
* Trigger actions when mouse is released
* @param {Object} e The event object
*/
handleMouseup() {
this.mousedown = false;
this.dragOffsetX = 0;
this.dragOffsetY = 0;
},
/**
* Trigger actions when mouse is pressed
* @param {Object} e The event object
*/
handleMousedown(e) {
if (!e.touches && e.cancelable) e.preventDefault();
const point = this.getEventPoint(e);
if (!point) return;
this.mousedown = true;
this.dragStartX = point.clientX;
this.dragStartY = point.clientY;
},
/**
* Trigger actions when mouse is pressed and then moved (mouse drag)
* @param {Object} e The event object
*/
handleMousemove(e) {
if (!this.mousedown) return;
const point = this.getEventPoint(e);
if (!point) return;
const eventPosX = point.clientX;
const eventPosY = point.clientY;
const deltaX = this.dragStartX - eventPosX;
const deltaY = this.dragStartY - eventPosY;
this.dragOffsetX = deltaX;
this.dragOffsetY = deltaY;
if (Math.abs(this.dragOffsetY) > Math.abs(this.dragOffsetX)) return;
if (this.dragOffsetX > this.minSwipeDistance) {
this.handleMouseup();
this.goNext();
} else if (this.dragOffsetX < -this.minSwipeDistance) {
this.handleMouseup();
this.goPrev();
}
},
getEventPoint(e) {
return e.touches && e.touches[0] || e.changedTouches && e.changedTouches[0] || e;
},
addInteractionListeners() {
if (window.PointerEvent) {
this.$el.addEventListener("pointerdown", this.handleMousedown);
this.$el.addEventListener("pointerup", this.handleMouseup);
this.$el.addEventListener("pointercancel", this.handleMouseup);
this.$el.addEventListener("pointerleave", this.handleMouseup);
this.$el.addEventListener("pointermove", this.handleMousemove);
return;
}
this.$el.addEventListener("touchstart", this.handleMousedown);
this.$el.addEventListener("touchend", this.handleMouseup);
this.$el.addEventListener("touchcancel", this.handleMouseup);
this.$el.addEventListener("touchmove", this.handleMousemove);
this.$el.addEventListener("mousedown", this.handleMousedown);
this.$el.addEventListener("mouseup", this.handleMouseup);
this.$el.addEventListener("mouseleave", this.handleMouseup);
this.$el.addEventListener("mousemove", this.handleMousemove);
},
removeInteractionListeners() {
if (window.PointerEvent) {
this.$el.removeEventListener("pointerdown", this.handleMousedown);
this.$el.removeEventListener("pointerup", this.handleMouseup);
this.$el.removeEventListener("pointercancel", this.handleMouseup);
this.$el.removeEventListener("pointerleave", this.handleMouseup);
this.$el.removeEventListener("pointermove", this.handleMousemove);
return;
}
this.$el.removeEventListener("touchstart", this.handleMousedown);
this.$el.removeEventListener("touchend", this.handleMouseup);
this.$el.removeEventListener("touchcancel", this.handleMouseup);
this.$el.removeEventListener("touchmove", this.handleMousemove);
this.$el.removeEventListener("mousedown", this.handleMousedown);
this.$el.removeEventListener("mouseup", this.handleMouseup);
this.$el.removeEventListener("mouseleave", this.handleMouseup);
this.$el.removeEventListener("mousemove", this.handleMousemove);
},
/**
* A mutation observer is used to detect changes to the containing node
* in order to keep the magnet container in sync with the height its reference node.
*/
attachMutationObserver() {
const MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
if (MutationObserver) {
const config = {
childList: true,
characterData: true,
subtree: true
};
this.mutationObserver = new MutationObserver(() => {
this.$nextTick(() => {
this.computeData();
});
});
if (this.$el) this.mutationObserver.observe(this.$el, config);
}
},
detachMutationObserver() {
if (this.mutationObserver) this.mutationObserver.disconnect();
},
/**
* Get the number of slides
* @return {Number} Number of slides
*/
getSlideCount() {
const defaultSlot = this.$slots.default;
if (!defaultSlot) return 0;
return countSlides(defaultSlot());
},
/**
* Calculate slide with and keep defined aspect ratio
* @return {Number} Aspect ratio number
*/
calculateAspectRatio(width, height) {
return Math.min(width / height);
},
/**
* Re-compute the number of slides and current slide
*/
computeSlideData(firstRun) {
this.total = this.getSlideCount();
if (this.total === 0) {
this.currentIndex = 0;
return;
}
if (firstRun || this.currentIndex >= this.total) this.currentIndex = getStartIndex(this.startIndex, this.total);
},
computeData(firstRun) {
this.computeSlideData(firstRun);
this.viewport = this.$el.clientWidth;
},
setSize() {
this.viewport = this.$el.clientWidth;
this.$el.style.height = this.slideHeight + "px";
const slider = this.$el.querySelector(".carousel-3d-slider");
if (slider) {
slider.style.width = this.slideWidth + "px";
slider.style.height = this.slideHeight + "px";
}
}
},
mounted() {
if (isBrowser) {
this.computeData(true);
this.attachMutationObserver();
window.addEventListener("resize", this.setSize);
this.addInteractionListeners();
}
},
beforeUnmount() {
if (isBrowser) {
this.detachMutationObserver();
this.removeInteractionListeners();
window.removeEventListener("resize", this.setSize);
}
clearTimeout(this.animationTimer);
this.clearNavigationTimers();
}
};
var _hoisted_1 = ["aria-label"];
function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
const _component_controls = (0, vue.resolveComponent)("controls");
const _component_dots = (0, vue.resolveComponent)("dots");
return (0, vue.openBlock)(), (0, vue.createElementBlock)("div", {
class: "carousel-3d-container",
style: (0, vue.normalizeStyle)({ height: $options.slideHeight + "px" }),
role: "region",
"aria-roledescription": "carousel",
"aria-label": $props.ariaLabel,
tabindex: "0",
onKeydown: [_cache[0] || (_cache[0] = (0, vue.withKeys)((0, vue.withModifiers)((...args) => $options.goPrev && $options.goPrev(...args), ["prevent"]), ["left"])), _cache[1] || (_cache[1] = (0, vue.withKeys)((0, vue.withModifiers)((...args) => $options.goNext && $options.goNext(...args), ["prevent"]), ["right"]))]
}, [
(0, vue.createElementVNode)("div", {
class: "carousel-3d-slider",
style: (0, vue.normalizeStyle)({
width: $options.slideWidth + "px",
height: $options.slideHeight + "px"
})
}, [(0, vue.renderSlot)(_ctx.$slots, "default", {}, void 0, true)], 4),
$props.controlsVisible ? ((0, vue.openBlock)(), (0, vue.createBlock)(_component_controls, {
key: 0,
"next-html": $props.controlsNextHtml,
"prev-html": $props.controlsPrevHtml,
width: $props.controlsWidth,
height: $props.controlsHeight
}, {
prev: (0, vue.withCtx)((slotProps) => [(0, vue.renderSlot)(_ctx.$slots, "prev", (0, vue.normalizeProps)((0, vue.guardReactiveProps)(slotProps)), void 0, true)]),
next: (0, vue.withCtx)((slotProps) => [(0, vue.renderSlot)(_ctx.$slots, "next", (0, vue.normalizeProps)((0, vue.guardReactiveProps)(slotProps)), void 0, true)]),
_: 3
}, 8, [
"next-html",
"prev-html",
"width",
"height"
])) : (0, vue.createCommentVNode)("", true),
$props.dots ? ((0, vue.openBlock)(), (0, vue.createBlock)(_component_dots, {
key: 1,
position: $props.dotsPosition
}, null, 8, ["position"])) : (0, vue.createCommentVNode)("", true)
], 44, _hoisted_1);
}
var Carousel3d_default = /*#__PURE__*/ _plugin_vue_export_helper_default(_sfc_main, [["render", _sfc_render], ["__scopeId", "data-v-db4a8480"]]);
//#endregion
//#region src/carousel-3d/index.js
var install = (app) => {
app.component("carousel3d", Carousel3d_default);
app.component("slide", Slide_default);
};
var carousel_3d_default = { install };
//#endregion
exports.Carousel3d = Carousel3d_default;
exports.Slide = Slide_default;
exports.default = carousel_3d_default;
});
//# sourceMappingURL=carousel-3d.umd.js.map