import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { computed, makeObservable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { Utils, emptyFunction, returnFalse, returnZero } from '../../../Utils'; import { Doc, DocListCast } from '../../../fields/Doc'; import { Id } from '../../../fields/FieldSymbols'; import { DocCast, NumCast, ScriptCast, StrCast } from '../../../fields/Types'; import { DocumentType } from '../../documents/DocumentTypes'; import { DragManager } from '../../util/DragManager'; import { SelectionManager } from '../../util/SelectionManager'; import { StyleProp } from '../StyleProvider'; import { DocumentView } from '../nodes/DocumentView'; import { FocusViewOptions } from '../nodes/FieldView'; import './CollectionCarousel3DView.scss'; import { CollectionSubView } from './CollectionSubView'; const { CAROUSEL3D_CENTER_SCALE, CAROUSEL3D_SIDE_SCALE, CAROUSEL3D_TOP } = require('../global/globalCssVariables.module.scss'); @observer export class CollectionCarousel3DView extends CollectionSubView() { @computed get scrollSpeed() { return this.layoutDoc._autoScrollSpeed ? NumCast(this.layoutDoc._autoScrollSpeed) : 1000; //default scroll speed } constructor(props: any) { super(props); makeObservable(this); } private _dropDisposer?: DragManager.DragDropDisposer; componentWillUnmount() { this._dropDisposer?.(); } protected createDashEventsTarget = (ele: HTMLDivElement | null) => { this._dropDisposer?.(); if (ele) { this._dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.layoutDoc); } }; @computed get carouselItems() { return this.childLayoutPairs.filter(pair => pair.layout.type !== DocumentType.LINK); } centerScale = Number(CAROUSEL3D_CENTER_SCALE); panelWidth = () => this._props.PanelWidth() / 3; panelHeight = () => this._props.PanelHeight() * Number(CAROUSEL3D_SIDE_SCALE); onChildDoubleClick = () => ScriptCast(this.layoutDoc.onChildDoubleClick); isContentActive = () => this._props.isSelected() || this._props.isContentActive() || this._props.isAnyChildContentActive(); isChildContentActive = () => (this.isContentActive() ? true : false); childScreenToLocal = () => this._props // document's left is the panel shifted by the doc's index * panelWidth/#docs. But it scales by centerScale around its center, so it's left moves left by the distance of the left from the center (panelwidth/2) * the scale delta (centerScale-1) .ScreenToLocalTransform() // the top behaves the same way ecept it's shifted by the 'top' amount specified for the panel in css and then by the scale factor. .translate(-this.panelWidth() + ((this.centerScale - 1) * this.panelWidth()) / 2, -((Number(CAROUSEL3D_TOP) / 100) * this._props.PanelHeight()) + ((this.centerScale - 1) * this.panelHeight()) / 2) .scale(1 / this.centerScale); focus = (anchor: Doc, options: FocusViewOptions) => { const docs = DocListCast(this.Document[this.fieldKey ?? Doc.LayoutFieldKey(this.Document)]); if (anchor.type !== DocumentType.CONFIG && !docs.includes(anchor)) return; options.didMove = true; const target = DocCast(anchor.annotationOn) ?? anchor; const index = docs.indexOf(target); index !== -1 && (this.layoutDoc._carousel_index = index); return undefined; }; @computed get content() { const currentIndex = NumCast(this.layoutDoc._carousel_index); const displayDoc = (childPair: { layout: Doc; data: Doc }) => { return ( ); }; return this.carouselItems.map((childPair, index) => { return (
{displayDoc(childPair)}
); }); } changeSlide = (direction: number) => { SelectionManager.DeselectAll(); this.layoutDoc._carousel_index = (NumCast(this.layoutDoc._carousel_index) + direction + this.carouselItems.length) % this.carouselItems.length; }; onArrowClick = (direction: number) => { this.changeSlide(direction); !this.layoutDoc.autoScrollOn && (this.layoutDoc.showScrollButton = direction === 1 ? 'fwd' : 'back'); // while autoscroll is on, keep the other autoscroll button hidden !this.layoutDoc.autoScrollOn && this.fadeScrollButton(); // keep pause button visible while autoscroll is on }; interval?: number; startAutoScroll = (direction: number) => { this.interval = window.setInterval(() => { this.changeSlide(direction); }, this.scrollSpeed); }; stopAutoScroll = () => { window.clearInterval(this.interval); this.interval = undefined; this.fadeScrollButton(); }; toggleAutoScroll = (direction: number) => { this.layoutDoc.autoScrollOn = this.layoutDoc.autoScrollOn ? false : true; this.layoutDoc.autoScrollOn ? this.startAutoScroll(direction) : this.stopAutoScroll(); }; fadeScrollButton = () => { window.setTimeout(() => { !this.layoutDoc.autoScrollOn && (this.layoutDoc.showScrollButton = 'none'); //fade away after 1.5s if it's not clicked. }, 1500); }; @computed get buttons() { return (
this.onArrowClick(-1)} />
this.onArrowClick(1)} /> {/* {this.autoScrollButton} */}
); } @computed get autoScrollButton() { const whichButton = this.layoutDoc.showScrollButton; return ( <>
this.toggleAutoScroll(-1)}> {this.layoutDoc.autoScrollOn ? : }
this.toggleAutoScroll(1)}> {this.layoutDoc.autoScrollOn ? : }
); } @computed get dots() { return this.carouselItems.map((_child, index) =>
(this.layoutDoc._carousel_index = index)} />); } @computed get translateX() { const index = NumCast(this.layoutDoc._carousel_index); return this.panelWidth() * (1 - index); } render() { return (
{this.content}
{this.buttons}
{this.dots}
); } }