this.move(1)}/>
this.closeSelf()}/>
);
this.container = slot.querySelector(`[part="content"]`);
let mouseMoveDisposable: Disposable;
let mouseUpDisposable: Disposable;
const scrollView = this.container;
scrollView.addEventListener("dragstart", (ev: DragEvent) => {
ev.preventDefault();
ev.stopImmediatePropagation();
});
scrollView.addEventListener("wheel", (e: WheelEvent) => {
const slotted = this.getSlottedElement(e.target as HTMLElement);
if (!slotted) {
return;
}
e.preventDefault();
e.stopImmediatePropagation();
const diff = e.deltaY < 0 ? 50 : -50;
this.updateZoom(slotted, diff, e.clientX, e.clientY);
});
scrollView.addEventListener("scroll", () => {
if (this.last) {
this.clearScale(this.last);
}
} , { passive: true } );
let previous: {x: number, y: number};
let touchMoveDisposable;
let touchEndDisposable;
let scale = 0;
let previousDistance = undefined;
scrollView.addEventListener("touchstart", (evs: TouchEvent) => {
const slottedElement = this.getSlottedElement(evs.target as HTMLElement);
if (!slottedElement) {
return;
}
if (evs.touches.length < 2) {
return;
}
previous = center(evs);
evs.preventDefault();
evs.stopImmediatePropagation();
touchMoveDisposable ??= this.bindEvent(scrollView, "touchmove", (ev: TouchEvent) => {
if (ev.touches.length < 2) {
return;
}
ev.preventDefault();
ev.stopImmediatePropagation();
const ld = findLargestDistance(ev.touches);
const first = ld.t1;
const second = ld.t2;
const newScale = ld.distance;
if (previousDistance === void 0) {
previousDistance = newScale;
return;
}
if (previousDistance === newScale) {
return;
}
const anchorX = ((first.clientX + second.clientX) / 2); // - rect.left;
const anchorY = ((first.clientY + second.clientY) / 2); // - rect.top;
scale = newScale - previousDistance;
previousDistance = newScale;
this.updateZoom(slottedElement, scale, anchorX, anchorY);
});
touchEndDisposable ??= this.bindEvent(scrollView, "touchend", (ev: TouchEvent) => {
if (ev.touches.length <2) {
return;
}
ev.preventDefault();
ev.stopImmediatePropagation?.();
touchMoveDisposable?.dispose();
touchEndDisposable?.dispose();
touchMoveDisposable = undefined;
touchEndDisposable = undefined;
previousDistance = undefined;
});
});
scrollView.addEventListener("mousedown", (de: MouseEvent) => {
const slottedElement = this.getSlottedElement(de.target as HTMLElement);
if (!slottedElement) {
return;
}
slottedElement.setAttribute("data-state", "grabbing");
previous = {
x: de.clientX,
y: de.clientY
};
mouseMoveDisposable ??= this.bindEvent(scrollView, "mousemove", (e: MouseEvent) => {
e.preventDefault();
e.stopImmediatePropagation();
const cp = { x: e.clientX, y: e.clientY };
const diffX = previous.x - cp.x;
const diffY = previous.y - cp.y;
previous = cp;
slottedElement.assignedSlot.scrollBy(diffX, diffY);
});
mouseUpDisposable ??= this.bindEvent(scrollView, "mouseup", (e: MouseEvent) => {
e.preventDefault();
e.stopImmediatePropagation();
slottedElement.removeAttribute("data-state");
mouseMoveDisposable[Symbol.dispose]();
mouseUpDisposable[Symbol.dispose]();
mouseMoveDisposable = null;
mouseUpDisposable = null;
});
});
}
getSlottedElement(target: HTMLElement): HTMLElement {
while(target && !target.assignedSlot) {
target = target.parentElement;
}
if (target.assignedSlot) {
return target;
}
return null;
}
closeSelf() {
const { last } = this;
if (last) {
this.clearScale(last);
return;
}
this.remove();
}
move(n: number) {
const { last, container } = this;
if (last) {
this.clearScale(last);
}
container.scrollBy({
left: n * container.offsetWidth,
behavior: "smooth"
});
}
async onFirstPrepare() {
if (!this.selected) {
return;
}
this.selected.scrollIntoView({
block: "nearest",
inline: "center",
behavior: "instant"
})
this.selected = null;
}
onChildAdded(child: HTMLElement) {
const slot = XNode.append(this.container,
) as HTMLSlotElement;
slot.assign(child);
// child.onwheel = (e: WheelEvent) => {
// const target = e.target as HTMLElement;
// const diff = e.deltaY < 0 ? 50 : -50;
// e.preventDefault();
// e.stopImmediatePropagation();
// this.updateZoom(target, diff, e.offsetX, e.offsetY )
// };
}
onChildRemoved(child: Node) {
}
private updateZoom(target: HTMLElement, scaleDiff, anchorX, anchorY ) {
this.container.style.scrollSnapType = "none";
this.last = target;
const { clientWidth } = this;
let scale = parseInt(target.getAttribute("last-scale") || "0", 10) + scaleDiff;
if (scale <= 0) {
scale = 0;
}
target.setAttribute("last-scale", scale);
if (scale === 0) {
this.clearScale(target);
return;
}
const { assignedSlot } = target;
// target.assignedSlot.style.position = "absolute";
assignedSlot.style.overflow = "auto";
assignedSlot.style.scrollSnapAlign = "unset";
assignedSlot.style.scrollSnapStop = "unset";
assignedSlot.style.scrollSnapType = "unset";
this.container.style.scrollSnapType = "unset";
// this.container.style.gridColumn = "1 / span 3";
target.style.scrollSnapAlign = "unset";
target.style.scrollSnapStop = "unset";
target.style.scrollSnapType = "unset";
// target.assignedSlot.style.zIndex = "1000";
const scaleFactor = (clientWidth + scale) / clientWidth;
// /** old one working in desktop */
// const e = target.getBoundingClientRect();
// target.style.width = scaleFactor * 100 + "%";
// target.style.height = scaleFactor * 100 + "%";
// const moved = Rectangle.from({
// x: 0,
// y: 0,
// width: e.width,
// height: e.height
// })
// .move(assignedSlot.scrollLeft,assignedSlot.scrollTop)
// .scale(scaleFactor, anchorX, anchorY);
// assignedSlot.scrollLeft -= moved.left;
// assignedSlot.scrollTop -= moved.top;
target.style.transformOrigin = `${anchorX}px ${anchorY}px`;
target.style.transform = `scale(${scaleFactor})`;
const e = target.getBoundingClientRect();
// console.log([e.left, e.top]);
const left = -e.left;
const top = -e.top;
target.style.transformOrigin = "0 0";
const de = target.getBoundingClientRect();
// console.log([de.left, de.top]);
assignedSlot.scrollTo({ left: left + de.left, top: top + de.top , behavior: "instant" });
}
private clearScale(target: HTMLElement) {
const { assignedSlot: { style: slotStyle } } = target;
this.container.style.removeProperty("scroll-snap-type");
// this.container.style.removeProperty("grid-column");
slotStyle.removeProperty("overflow");
slotStyle.removeProperty("scroll-snap-align");
slotStyle.removeProperty("scroll-snap-stop");
slotStyle.removeProperty("scroll-snap-type");
target.removeAttribute("last-scale");
target.style.removeProperty("scroll-snap-align");
target.style.removeProperty("scroll-snap-stop");
target.style.removeProperty("scroll-snap-type");
target.style.removeProperty("width");
target.style.removeProperty("height");
// target.assignedSlot.style.removeProperty("position");
// target.assignedSlot.style.removeProperty("z-index");
target.style.transform = "";
this.last = null;
}
}
customElements.define("full-screen-image-gallery", FullScreenImageGallery);