( function() { var app = window.app = window.app || {}; window.ccc = console.log; // //\\ configuration ////////////////////////// let WRAPPER_WIDTH = 1020; let WRAPPER_HEIGHT = 800; let WRAPPER_OBZERVER_Z = 1500; //This parameter if for envelope. //If has been done to facilitate mouse hover on entire carousel, //but now it seems non important //its time consuming to program outer dimenstion of //3d carousel, so for proof-case we set it in configuration; let EMPIRICAL_WIDTH = 1.5; let MASTER = { animDuration : 0, //180000, //set 0 - to disable width : 2, //1020, //small value, 2, is chosen to not interfere with mouse hover on sprite which is crossing the MASTER height : 2, //800, //small value is for hover ... distanceToCarousel : 300, //20000; //300; observerZ : 400, perspectiveOrigin : [ 510, 400 ] }; let CAROUSELS = [ { facetsCount : 8, animationCycleDuration : 50, //sec position : { left : 100, top : 0, zz : 0 }, //no zz yet rotation : 'rotateY', //[ 0, 1, 0 ], spriteWidth : 450, spriteHeight : 300, rotateClockwise : false, //true; //false = right-to-left along x axis; rotation around y axis imageList : app.horizontalFiles }, { facetsCount : 8, animationCycleDuration : 180, //sec position : { left : 600, top : 0, zz : 0 }, rotation : 'rotateX', //[ 1, 0, 0 ], spriteWidth : 400, spriteHeight : 600, rotateClockwise : true, //true; //false = right-to-left along x axis; rotation around y axis imageList : app.verticalFiles } ]; //:inner config let SPRITE_TRANSPARENT_BACKGROUND = false; let DIGITS_FOR_CSS = 8; // \\// configuration ////////////////////////// //:spawning config let rad2deg = Math.PI / 180; let carDistance = MASTER.distanceToCarousel; let tabIndex = 1; ///parents let masterMoveStyle = !MASTER.animDuration ? '' : ` border: 1px solid grey; perspective: ${WRAPPER_OBZERVER_Z}px; perspective-origin: ${MASTER.perspectiveOrigin[0]}px ${MASTER.perspectiveOrigin[1]}px; transform-style: preserve-3d;`; let wrapperStyle =` #wrapper { position: relative; padding: 0px; margin: auto; left: 0; top: 0; background-color: transparent; width: ${WRAPPER_WIDTH}px; height: ${WRAPPER_HEIGHT}px; overflow: visible; color: white; ${masterMoveStyle} } `; let masterStyle =` #master { position: absolute; padding: 0px; margin: 0px; top: 80px; border 1px solid #AAAAAA; background-color: transparent; width: ${MASTER.width}px; height: ${MASTER.height}px; overflow: visible; color: white; perspective: ${MASTER.observerZ}px; perspective-origin: ${MASTER.perspectiveOrigin[ 0 ]}px ${MASTER.perspectiveOrigin[ 1 ]}px; transform-style: preserve-3d; } `; let carouselEnvelope = ` .carousel-envelope { position: absolute; /* good for debug */ border: 1px solid #aaaaaa; background-color: transparent; perspective: ${WRAPPER_OBZERVER_Z}px; perspective-origin: ${MASTER.perspectiveOrigin[0]}px ${MASTER.perspectiveOrigin[1]}px; transform-style: preserve-3d; }`; let mstAnim = !MASTER.animDuration ? '' : ` @keyframes move_master { from { transform: rotateY(0deg); } to { transform: rotateY(360deg); } } #master { -webkit-animation: ${MASTER.animDuration}s linear 0s infinite normal move_master; animation: ${MASTER.animDuration}s linear 0s infinite normal move_master; }`; // //\\ helpers //works but not with :hover: filter: grayscale( ${ 0.8 * floatPhase + 0.199} ); function makeTurnPhase( rotateAxis, phase, turn, floatPhase ) { //, zIndex ) { return ` ${phase}% { transform: ${rotateAxis}(${turn}deg); }`; }; // \\// helpers function makeCarousel ( cId, crs ) { let FACETS_COUNT = crs.facetsCount; let phaseStep = 100 / FACETS_COUNT; let turnStep = 360 / FACETS_COUNT; let rotationDir = crs.rotateClockwise ? 1 : -1; let facets2 = FACETS_COUNT / 2; let centerShiftX = 0; let centerShiftY = 0; let spriteLeft = 0; let spriteTop = 0; let rotationRadius; //from center of facet, not from its edge; let envelopeLeft = crs.position.left; let envelopeTop = crs.position.top; let envelopeWidth = crs.spriteWidth; let envelopeHeight = crs.spriteHeight; if( crs.rotation === 'rotateX' ) { ////around axis X centerShiftY = 0.5 * crs.spriteHeight; rotationRadius = centerShiftY / Math.tan( rad2deg * turnStep / 2 ); let radiusProjection = rotationRadius * carDistance / ( carDistance + rotationRadius ); let effSize = 2 * radiusProjection * EMPIRICAL_WIDTH; spriteTop = effSize / 2 - centerShiftY; envelopeTop += -spriteTop; envelopeHeight = effSize; envelopeWidth = crs.spriteWidth; //patch; } else { centerShiftX = 0.5 * crs.spriteWidth; rotationRadius = centerShiftX / Math.tan( rad2deg * turnStep / 2 ); let radiusProjection = rotationRadius * carDistance / ( carDistance + rotationRadius ); let effSize = 2 * radiusProjection * EMPIRICAL_WIDTH; spriteLeft = effSize / 2 - centerShiftX; envelopeLeft += -spriteLeft; envelopeWidth = effSize; envelopeHeight = crs.spriteHeight; //patch } let rotation = crs.rotation; let anim = ''; let sprites = ''; let html = ''; let spriteStyle = ` .sprite-${cId} { position: absolute; height: ${crs.spriteHeight}px; width: ${crs.spriteWidth}px; margin: 0px; padding: 0px; left: ${spriteLeft}px; top: ${spriteTop}px; border-radius: 15px; background-color: transparent; background-size: cover; color: white; filter: grayscale( 1 ); /*. sprite rotates over this point */ transform-origin: ${centerShiftX.toFixed(10)}px ${centerShiftY.toFixed(10)}px ${(-rotationRadius).toFixed(10)}px; } `; let envelopeStyles = ` #carousel-envelope-${cId} { width: ${envelopeWidth}px; height: ${envelopeHeight}px; left: ${envelopeLeft}px; top: ${envelopeTop}px; }`; ///prepare child sprites for( let iFacet = 0; iFacet < FACETS_COUNT; iFacet++ ) { let sId = `sprite-${cId}-${iFacet}` let an = ''; for( let iPhase = 0; iPhase <= FACETS_COUNT; iPhase++ ) { let absPhase = iPhase + iFacet; let ePhase = absPhase % FACETS_COUNT; let floatPhase = 2 * Math.abs( ePhase / FACETS_COUNT ); an += makeTurnPhase( rotation, ( iPhase * phaseStep ).toFixed( DIGITS_FOR_CSS ), ( rotationDir * absPhase * turnStep ).toFixed( DIGITS_FOR_CSS ), floatPhase ); } anim += ` @keyframes move_sprite_${cId}_${iFacet} {${an} }`; let color; if( SPRITE_TRANSPARENT_BACKGROUND ) { color = ''; } else { let colorGrain = FACETS_COUNT / 3; let cMas = 3 * iFacet / FACETS_COUNT; let colorGroup = Math.floor( cMas ); let subColor = cMas - colorGroup + 1/3; let subColorValue = [ [ 254, 0, 0 ], [ 0, 254, 0 ], [ 0, 0, 254 ] ]; let rr = subColorValue[ colorGroup ][0] * subColor; let gg = subColorValue[ colorGroup ][1] * subColor; let bb = subColorValue[ colorGroup ][2] * subColor; let forColor = 'rgb(' + rr.toFixed(0) + ', ' + gg.toFixed(0) + ', ' + bb.toFixed(0) + ')'; color = ` background-color: ${forColor};`; } ////sprites let wAn = `${crs.animationCycleDuration}s linear 0s infinite normal move_sprite_${cId}_${iFacet}`; let imgInfo = crs.imageList; // //\\ sets individual sprite CSS sprites += ` #${sId} {${color} background-image: url("${imgInfo.path}/${imgInfo.list[ iFacet ][0]}"); -webkit-animation: ${wAn}; animation: ${wAn}; } /* #carousel-envelope-${cId}:hover #${sId} {${color} background-image: url("${imgInfo.path}/${imgInfo.list[ iFacet ][0]}"); -webkit-animation-play-state: paused; animation-play-state: paused; } */ #carousel-envelope-${cId}:hover { /* background-color : red; */ } /* ********************************************************** * /* Edge catches this block but still no pause ... what's wrong? */ /* the verdict seems: all devs gave this up in Edge: https://stackoverflow.com/questions/34192358/why-does-animation-pause-on-hover-work-in-ie-but-not-chrome-or-edge */ #carousel-envelope-${cId}:hover div.sprite-${cId}#${sId} { -webkit-animation-play-state: paused; animation-play-state: paused; border : 2px solid green; } /* this is respected in Edge */ /* div.sprite-${cId}#${sId} { -webkit-animation-play-state: paused; animation-play-state: paused; border : 2px solid green; } */ /* ********************************************************** */ #${sId}:hover { filter: grayscale( 0 ); } `; ///this works, but ugly /* sprites += ` #${sId}:focus { height: ${1.5 * crs.spriteHeight}px; width: ${0.5 * crs.spriteWidth}px; }`; */ /* no dice: transform: rotateX(0deg); */ sprites += ` #${sId}:focus::before { position: absolute; font-size: 200%; top: 50%; left: 50%; padding: 10px; border-radius: 15px; background-color: rgba(0, 0, 0, 0.4); transform: translate(-50%, -50%); content: '${imgInfo.list[ iFacet ][ 1 ]}'; }`; html += `
`; } app.cssAnimation += mstAnim + envelopeStyles + spriteStyle + anim + sprites; app.html += `