Published
Edited
Mar 28, 2022
Importers
1 star
Insert cell
Insert cell
Insert cell
Insert cell
function newBasicSlideDeck({
count = 0,
id,
activate = () => {},
deactivate = () => {},
handleError = console.error,
width = 500,
height = width / 1.6,
delay = 100,
...options
}) {
id = id || newId();
const div = document.createElement("div");
div.innerHTML = `
<!-- Slider main container -->
<div class="swiper" id="${id}">
<!-- Slides are in an additional required wrapper -->
<div class="swiper-wrapper"></div>

<!-- Pagination -->
<div class="swiper-pagination"></div>

<!-- Navigation buttons -->
<div class="swiper-button-prev"></div>
<div class="swiper-button-next"></div>

<!-- Scrollbar -->
<div class="swiper-scrollbar"></div>
</div>

<style>
#${id} {
width: ${width}px;
height: ${height}px;
}
</style>
`;
const rootElm = div.querySelector(".swiper");
const wrapperElm = rootElm.querySelector(".swiper-wrapper");
for (let i = 0; i < count; i++) {
const element = document.createElement("div");
element.classList.add("swiper-slide");
wrapperElm.appendChild(element);
}

let info;
let promise = Promise.resolve();
const onUpdate = debounce((swiper) => {
promise = promise.then(async () => {
try {
const element = swiper.slides[swiper.realIndex];
if (info && element === info.element) return;
if (info) {
await deactivate(info);
info = null;
}
if (!element) return;
info = {
element,
slideElement: element,
index: swiper.realIndex,
swiper,
width,
height,
...options
};
await activate(info);
div.dispatchEvent(new CustomEvent("input"));
} catch (error) {
handleError(error);
}
});
}, delay);
const swiper = new Swiper(rootElm, {
// Optional parameters
// direction: "horizontal", // "vertical",
direction: "horizontal",
...options,

keyboard: {
enabled: true,
...options.keyboard
},

// If we need pagination
pagination: {
...options.pagination,
el: rootElm.querySelector(".swiper-pagination"),
// clickable: true,
type: "fraction"
},

// Navigation arrows
navigation: {
...options.navigation,
nextEl: rootElm.querySelector(".swiper-button-next"),
prevEl: rootElm.querySelector(".swiper-button-prev")
},

// And if we need scrollbar
scrollbar: {
draggable: true, // draggable scrollbar
snapOnRelease: true,
...options.scrollbar,
el: div.querySelector(".swiper-scrollbar")
},

on: {
beforeSlideChangeStart: onUpdate,
slideChange: onUpdate
}
});
Object.defineProperty(div, "value", {
get: () => (info ? info.index : -1),
set: (value = 0) => {
!isNaN(value) && swiper.slideTo(value);
}
});
return Object.assign(div, { swiper });

function newId(prefix = "id") {
const ns = newId;
const base = (ns._base = ns._base || Date.now());
const id = (ns._counter = (ns._counter || 0) + 1);
return `${prefix}-${base}-${id}`;
}

function debounce(func, delay) {
let id;
return (...args) => (
clearTimeout(id), (id = setTimeout(() => func(...args), delay))
);
}
}
Insert cell
function newSlideDeck(options) {
return newBasicSlideDeck(getSlidesScaleParams(options));
}
Insert cell
function getSlidesScaleParams({
activate = () => {},
deactivate = () => {},
width = 1024,
height = width / 1.6,
slideWidth = width,
slideHeight = (slideWidth * height) / width,
...params
}) {
function getSize(style, top, right, bottom, left) {
return {
left: parseFloat(style[left]) || 0,
right: parseFloat(style[right]) || 0,
top: parseFloat(style[top]) || 0,
bottom: parseFloat(style[bottom]) || 0
};
}
function updateOptions(options) {
// https://www.javascripttutorial.net/javascript-dom/javascript-width-height/
const slideElement = options.element._slideElm;
const style = getComputedStyle(options.element);
const padding = getSize(
style,
"paddingTop",
"paddingRight",
"paddingBottom",
"paddingLeft"
);
const border = getSize(
style,
"borderTopWidth",
"borderRightWidth",
"borderBottomWidth",
"borderLeftWidth"
);
const width =
parseFloat(style.width) -
padding.left -
padding.right -
border.left -
border.right -
0;
const height =
parseFloat(style.height) -
padding.top -
padding.bottom -
border.top -
border.bottom -
0;

const slideScaleX = width / slideWidth;
const slideScaleY = height / slideHeight;
return { ...options, slideElement, slideScaleX, slideScaleY };
}
return {
...params,
width,
height,
slideWidth,
slideHeight,
activate: async (options) => {
const { element, index } = options;
let slideElement = element._slideElm;
if (!slideElement) {
slideElement = element._slideElm = document.createElement("div");
element.appendChild(slideElement);
Object.assign(element.style, {
position: "relative",
padding: 0
});
Object.assign(slideElement.style, {
position: "absolute",
top: 0,
left: 0,
transformOrigin: "top left",
width: `${slideWidth}px`,
height: `${slideHeight}px`
});
}
options = updateOptions(options);
Object.assign(options.slideElement.style, {
transform: `scale(${options.slideScaleX}, ${options.slideScaleY})`
});
await activate(options);
},
deactivate: async (options) => {
await deactivate(updateOptions(options));
}
};
}
Insert cell
function newSlideDeckCss() {
return `
@import "https://cdn.jsdelivr.net/npm/swiper@8.0.7/swiper-bundle.css";

/* * /
:root {
--swiper-scrollbar-color: #eee;
--swiper-slide-border-color : #eee;
--swiper-slide-background-color: white;
--swiper-slide-border-width: 5px;
--swiper-slide-border-radius: 0.2em;
}
/* */

.swiper {
height: 100%;
}

.swiper .swiper-wrapper {
height: 100%;
}

.swiper .swiper-scrollbar {
background-color: var(--swiper-scrollbar-color, #eee);
}
.swiper .swiper-slide {
box-sizing: border-box;
border: var(--swiper-slide-border-width, 5px) solid var(--swiper-slide-border-color, #eee);
border-radius: var(--swiper-slide-border-radius, 0.2em);
background: var(--swiper-slide-background-color, white);
display: flex;
justify-content: center;
align-items: center;
}

.swiper.swiper-horizontal .swiper-slide {
height: calc(100% - 3px);
}

.swiper.swiper-vertical .swiper-slide {
width: calc(100% - 3px);
}
.swiper .swiper-scrollbar-drag {
background-color: var(--swiper-theme-color);
}
.swiper .swiper-button-next,
.swiper .swiper-button-next {
}

.swiper .swiper-pagination {
font-size: 1.2em;
background-color: rgba(255,255,255,0.4);
border-radius: var(--swiper-slide-border-radius);
color: rgba(0,0,0,0.4);
left: calc(50% - 2.5em);
width: 5em;
padding: 0.5em;
}
.swiper .swiper-pagination:hover {
background-color: rgba(255,255,255,1);
color: rgba(0,0,0,1);
}
`;
}
Insert cell
Insert cell
Swiper = {
return (await import("swiper@8.0.7/swiper-bundle.esm.browser.js")).default;
}
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more