@@ -1,18 +1,42 @@
function customTimeline ( ) {
// titres de parties dans le tableau
let mainpartTitless = document . querySelectorAll ( '.isMainPart' ) ;
for ( let mainpartTitles of mainpartTitless ) {
if ( mainpartTitles . nextElementSibling . classList . contains ( 'isSubPart' ) ) {
mainpartTitles . firstElementChild . firstElementChild . style . height = "1.5rem" ;
mainpartTitles . firstElementChild . style . marginBottom = "-0.25rem" ;
mainpartTitles . style . borderBottom = "0" ;
mainpartTitles . style . paddingBottom = "0" ;
mainpartTitles . nextElementSibling . style . paddingTop = "0" ;
let colors , titles , partTitles ;
let partDurations = [ ] ;
let totalTime ;
let tlContainer , tlContainerHeight ;
let partBlockHeights = [ ] ;
let activePartIndex = 0 ;
let steps = {
tlElSteps : [ ] ,
scrollSteps : [ ]
}
let previousScroll ;
let grabbing = false ;
let titresFrise ;
let cursor = document . querySelector ( '#cursor' ) ;
let titresCursor ;
let partRects ;
let isScrollingFromGrab = false ;
let prevPartIndex = 0 ;
let lastCallTimestamp = 0 ;
let timestampDebounce = 200 ;
// titres de parties dans le tableau
function setPartTitlesInPartition ( ) {
let mainpartTitles = document . querySelectorAll ( '.isMainPart' ) ;
for ( let mainpartTitle of mainpartTitles ) {
if ( mainpartTitle . nextElementSibling . classList . contains ( 'isSubPart' ) ) {
mainpartTitle . firstElementChild . firstElementChild . style . height = "1.5rem" ;
mainpartTitle . firstElementChild . style . marginBottom = "-0.25rem" ;
mainpartTitle . style . borderBottom = "0" ;
mainpartTitle . style . paddingBottom = "0" ;
mainpartTitle . nextElementSibling . style . paddingTop = "0" ;
}
}
// couleurs titres
let colors = [
}
// couleurs titres
function setPartsColors ( ) {
colors = [
{ 'red' : 'cf0118' } ,
{ 'blue1' : '0101c4' } ,
{ 'blue2' : '01049e' } ,
@@ -27,8 +51,8 @@ function customTimeline() {
{ 'pink1' : 'cf0118' } ,
{ 'pink2' : 'a10418' }
] ;
let titles = document . querySelectorAll ( '.isMainPart, .isSubPart' ) ;
let partTitles = [ ] ;
titles = document . querySelectorAll ( '.isMainPart, .isSubPart' ) ;
partTitles = [ ] ;
for ( let title of titles ) {
if ( ! title . nextElementSibling . classList . contains ( 'isSubPart' ) ) {
partTitles . push ( title ) ;
@@ -40,21 +64,23 @@ function customTimeline() {
}
partTitles [ i ] . firstElementChild . firstElementChild . style . backgroundColor = "#" + Object . values ( colors [ i ] ) [ 0 ] ;
}
// set parts rectangles
function convertToSeconds ( timeStr ) {
let [ hourStr , minStr ] = timeStr . split ( 'h' ) ;
if ( ! minStr ) {
minStr = hourStr ;
hourStr = '0' ;
}
minStr = minStr . replace ( '’ ' , ':' ) ;
minStr = minStr . replace ( "'" , ':' ) ;
const [ min , sec ] = minStr . split ( ':' ) ;
return parseInt ( hourStr ) * 3600 + parseInt ( min ) * 60 + parseInt ( sec ) ;
}
}
// set parts rectangles
function convertToSeconds ( timeStr ) {
let [ hourStr , minStr ] = timeStr . split ( 'h' ) ;
if ( ! minStr ) {
minStr = hourStr ;
hourStr = '0' ;
}
minStr = minStr . replace ( '’ ' , ':' ) ;
minStr = minStr . replace ( "'" , ':' ) ;
const [ min , sec ] = minStr . split ( ':' ) ;
return parseInt ( hourStr ) * 3600 + parseInt ( min ) * 60 + parseInt ( sec ) ;
}
function getPartsTimes ( ) {
let partTimesNodes = document . querySelectorAll ( 'body #app main tbody tr:not(.isContentPart) + tr:not(.isSubPart) td:first-of-type' ) ;
let partTimes = Array . from ( partTimesNodes ) ;
for ( let i = 0 ; i < partTimes . length ; i ++ ) {
@@ -62,98 +88,73 @@ function customTimeline() {
}
let lastTime = document . querySelectorAll ( 'body #app main tbody tr:last-of-type td:first-of-type' ) ;
partTimes . push ( convertToSeconds ( lastTime [ 0 ] . innerText ) ) ;
let partDurations = [ ] ;
for ( let i = 0 ; i < partTimes . length - 1 ; i ++ ) {
partDurations . push ( partTimes [ i + 1 ] - partTimes [ i ] ) ;
}
let totalTime = convertToSeconds ( lastTime [ 0 ] . innerText ) ;
let tlContainer , tlContainerHeight ;
let partBlockHeights = [ ] ;
let activePartIndex = 0 ;
function getAllHeights ( ) {
partBlockHeights = [ ] ;
tlContainer = document . querySelector ( '#timeline_container' ) ;
let header = document . querySelector ( 'header' ) , footer = document . querySelector ( 'footer' ) ;
tlContainer . style . height = ` calc(100vh - ${ header . offsetHeight } px - ${ footer . offsetHeight } px - 60px) ` ;
tlContainer . style . top = ` ${ document . querySelector ( 'header' ) . offsetHeight + 30 } px ` ;
tlContainerHeight = tlContainer . offsetHeight ;
for ( let partDuration of partDurations ) {
partBlockHeights . push ( partDuration / totalTime * tlContainerHeight ) ;
}
totalTime = convertToSeconds ( lastTime [ 0 ] . innerText ) ;
}
function getAllHeights ( ) {
partBlockHeights = [ ] ;
tlContainer = document . querySelector ( '#timeline_container' ) ;
let header = document . querySelector ( 'header' ) ;
let footer = document . querySelector ( 'footer' ) ;
tlContainer . style . height = ` calc(100vh - ${ header . offsetHeight } px - ${ footer . offsetHeight } px - 60px) ` ;
tlContainer . style . top = ` ${ header . offsetHeight + 30 } px ` ;
tlContainerHeight = tlContainer . offsetHeight ;
for ( let partDuration of partDurations ) {
partBlockHeights . push ( partDuration / totalTime * tlContainerHeight ) ;
}
getAllHeights ( ) ;
function drawFriseRects ( ) {
for ( let i = 0 ; i < partBlockHeights . length ; i ++ ) {
let partDiv = document . createElement ( 'div' ) ;
partDiv . style . width = "22px" ;
partDiv . style . height = partBlockHeights [ i ] + "px" ;
partDiv . style . backgroundColor = "#" + Object . values ( colors [ i ] ) [ 0 ] ;
partDiv . style . borderBottom = "solid 1px #010d19" ;
partDiv . style . borderTop = "solid 1px #010d19" ;
partDiv . style . transition = "width 0.3s ease-out" ;
partDiv . style . cursor = "pointer" ;
tlContainer . prepend ( partDiv ) ;
tlContainer . children [ 0 ] . addEventListener ( "mouseenter" , function ( ) {
let el = tlContainer . children [ tlContainer . children . length - 1 - i ] ;
if ( Array . from ( el . parentNode . children ) . length - Array . from ( el . parentNode . children ) . indexOf ( el ) - 1 != activePartIndex ) {
el . style . width = "32px" ;
toggleTitleHover ( i , 'show' ) ;
}
} ) ;
tlContainer . children [ 0 ] . addEventListener ( "mouseleave" , function ( ) {
let el = tlContainer . children [ tlContainer . children . length - 1 - i ] ;
if ( Array . from ( el . parentNode . children ) . length - Array . from ( el . parentNode . children ) . indexOf ( el ) - 1 != activePartIndex ) {
el . style . width = "22px" ;
}
toggleTitleHover ( i , 'hide' ) ;
} ) ;
tlContainer . children [ 0 ] . addEventListener ( "click" , function ( ) {
isScrollingFromGrab = false ;
titresFrise [ i ] . el . scrollIntoView ( { behavior : 'smooth' , block : 'center' } ) ;
} ) ;
}
}
function drawFriseRects ( ) {
for ( let i = 0 ; i < partBlockHeights . length ; i ++ ) {
let partDiv = document . createElement ( 'div' ) ;
partDiv . classList . add ( 'tlRectPart' ) ;
partDiv . style . height = partBlockHeights [ i ] + "px" ;
partDiv . style . backgroundColor = "#" + Object . values ( colors [ i ] ) [ 0 ] ;
tlContainer . prepend ( partDiv ) ;
tlContainer . children [ 0 ] . addEventListener ( "mouseenter" , function ( ) {
let el = tlContainer . children [ tlContainer . children . length - 1 - i ] ;
if ( Array . from ( el . parentNode . children ) . length - Array . from ( el . parentNode . children ) . indexOf ( el ) - 1 ! = activePartIndex ) {
el . style . width = "32px" ;
toggleTitleHover ( i , 'show' ) ;
}
} ) ;
tlContainer . children [ 0 ] . addEventListener ( "mouseleave" , function ( ) {
let el = tlContainer . children [ tlContainer . children . length - 1 - i ] ;
if ( Array . from ( el . parentNode . children ) . length - Array . from ( el . parentNode . children ) . indexOf ( el ) - 1 != activePartIndex ) {
el . style . width = "22px" ;
}
toggleTitleHover ( i , 'hide' ) ;
} ) ;
tlContainer . children [ 0 ] . addEventListener ( "click" , function ( ) {
isScrollingFromGrab = false ;
titresFrise [ i ] . el . scrollIntoView ( { behavior : 'smooth' , block : 'center' } ) ;
} ) ;
}
drawFriseRects ( ) ;
window . addEventListener ( 'resize' , ( ) => {
while ( tlContainer . lastChild ) {
tlContainer . removeChild ( tlContainer . lastChild ) ;
}
getAllHeights ( ) ;
drawFriseRects ( ) ;
setPartRects ( ) ;
} ) ;
// detect if is scrolling
let previousScroll ;
function isWindowScrolling ( ) {
let currentScroll = window . scrollY ;
if ( currentScroll !== previousScroll ) {
previousScroll = currentScroll ;
return true ;
} else {
return false ;
}
}
// detect if is scrolling
function isWindowScrolling ( ) {
let currentScroll = window . scrollY ;
if ( currentScroll !== previousScroll ) {
previousScroll = currentScroll ;
return true ;
} else {
return false ;
}
// titres parties frise
let titreFriseEl = document . createElement ( 'div' ) ;
let elements = Array . from ( document . querySelectorAll ( '.isMainPart, .isSubPart' ) ) ;
}
// titres parties frise
function displayTimelineTitles ( ) {
let mainWithoutSubAfter = [ ] ;
let mainWithSubAfter = [ ] ;
let subWithoutMainBefore = [ ] ;
let elements = Array . from ( document . querySelectorAll ( '.isMainPart, .isSubPart' ) ) ;
let lastMain = null ;
let grabbing = false ;
for ( let i = 0 ; i < elements . length ; i ++ ) {
let current = elements [ i ] ;
let next = elements [ i + 1 ] ;
@@ -173,7 +174,7 @@ function customTimeline() {
}
}
let titresFrise = [ ... mainWithoutSubAfter , ... mainWithSubAfter , ... subWithoutMainBefore ] ;
titresFrise = [ ... mainWithoutSubAfter , ... mainWithSubAfter , ... subWithoutMainBefore ] ;
titresFrise . sort ( ( a , b ) => a . index - b . index ) ;
@@ -185,6 +186,9 @@ function customTimeline() {
titresFrise . splice ( i , 1 ) ;
}
}
let titreFriseEl = document . createElement ( 'div' ) ;
titreFriseEl . setAttribute ( 'id' , 'titres_frise' ) ;
titreFriseEl . innerHTML = `
@@ -192,346 +196,331 @@ function customTimeline() {
<p> ${ titresFrise [ 0 ] . main } </p>
<p class="font-authentic-60"> ${ titresFrise [ 0 ] . sub } </p>
` ;
titreFriseEl . style . fontSize = '0.9em' ;
titreFriseEl . style . backgroundColor = 'rgba(1, 13, 25, 0.6)' ;
titreFriseEl . style . zIndex = '20' ;
titreFriseEl . style . position = 'fixed' ;
titreFriseEl . style . left = '60px' ;
titreFriseEl . style . width = '10vw' ;
titreFriseEl . style . lineHeight = '1.2' ;
titreFriseEl . style . marginTop = '-8px' ;
titreFriseEl . style . top = ` ${ document . querySelector ( '#timeline_container' ) . getBoundingClientRect ( ) . top } px ` ;
let main = document . querySelector ( '#main' ) ;
main . prepend ( titreFriseEl ) ;
// création et togle des titres au survol des div de la timeline
function drawFixedTitles ( ) {
let tlContainer = document . querySelector ( '#timeline_container' ) ;
let fixedTitlesContainer = document . createElement ( 'div' ) ;
fixedTitlesContainer . setAttribute ( 'id' , 'fixedTitlesContainer' ) ;
main . prepend ( fixedTitlesContainer ) ;
for ( let index = 0 ; index < titresFrise . length ; index ++ ) {
let titreFixedEl = document . createElement ( 'div' ) ;
titreFixedEl . style . position = 'fixed' ;
titreFixedEl . style . zIndex = 1 ;
titreFixedEl . style . display = 'none' ;
titreFixedEl . style . opacity = '0' ;
titreFixedEl . style . transition = 'opacity 0.3s ease-out' ;
titreFixedEl . style . width = '10vw' ;
titreFixedEl . style . top = ` ${ tlContainer . children [ index ] . getBoundingClientRect ( ) . top - 8 } px ` ;
titreFixedEl . style . left = '60px' ;
titreFixedEl . style . fontSize = '0.9em' ;
titreFixedEl . style . lineHeight = '1.2' ;
let titreFixedElContent = document . createElement ( 'p' ) ;
titreFixedElContent . innerHTML = `
<p> ${ titresFrise [ titresFrise . length - index - 1 ] . main } </p>
<p class="font-authentic-60"> ${ titresFrise [ titresFrise . length - index - 1 ] . sub } </p>
` ;
titreFixedElContent . style . backgroundColor = '#010d19' ;
titreFixedEl . append ( titreFixedElContent ) ;
let topGradient = document . createElement ( 'div' ) ;
topGradient . style . height = '10px' ;
topGradient . style . width = '100%' ;
topGradient . style . background = 'linear-gradient(to bottom, transparent, #010d19)' ;
titreFixedEl . prepend ( topGradient ) ;
let bottomGradient = document . createElement ( 'div' ) ;
bottomGradient . style . height = '10px' ;
bottomGradient . style . width = '100%' ;
bottomGradient . style . background = 'linear-gradient(to top, transparent, #010d19)' ;
titreFixedEl . append ( bottomGradient ) ;
fixedTitlesContainer . prepend ( titreFixedEl ) ;
}
titresCursor = document . querySelector ( '#titres_frise' ) ;
setTimeout ( ( ) => {
titreFriseEl . firstElementChild . innerText = getCurrentTime ( titresFrise [ 0 ] . el ) ;
} , 10 ) ;
}
// création et togle des titres au survol des div de la timeline
function drawFixedTitles ( ) {
let tlContainer = document . querySelector ( '#timeline_container' ) ;
let fixedTitlesContainer = document . createElement ( 'div' ) ;
fixedTitlesContainer . setAttribute ( 'id' , 'fixedTitlesContainer' ) ;
main . prepend ( fixedTitlesContainer ) ;
for ( let index = 0 ; index < titresFrise . length ; index ++ ) {
let titreFixedEl = document . createElement ( 'div' ) ;
titreFixedEl . classList . add ( 'tlFixedTitle' ) ;
titreFixedEl . style . top = ` ${ tlContainer . children [ index ] . getBoundingClientRect ( ) . top - 8 } px ` ;
let titreFixedElContent = document . createElement ( 'p' ) ;
titreFixedElContent . innerHTML = `
<p> ${ titresFrise [ titresFrise . length - index - 1 ] . main } </p>
<p class="font-authentic-60"> ${ titresFrise [ titresFrise . length - index - 1 ] . sub } </p>
` ;
titreFixedEl . append ( titreFixedElContent ) ;
fixedTitlesContainer . prepend ( titreFixedEl ) ;
}
drawFixedTitles ( ) ;
function toggleTitleHover ( elIndex , state ) {
let fixedTitlesContainer = document . querySelector ( '#fixedTitlesContainer' ) ;
let el = fixedTitlesContainer . children [ elIndex ] ;
if ( state === 'show' ) {
el . style . display = 'block' ;
setTimeout ( ( ) => {
el . style . opacity = '1' ;
} , 1 ) ;
} else if ( state === 'hide' ) {
el . style . opacity = '0' ;
setTimeout ( ( ) => {
el . style . display = 'none' ;
} , 300 ) ;
}
}
function toggleTitleHover ( elIndex , state ) {
let fixedTitlesContainer = document . querySelector ( '#fixedTitlesContainer' ) ;
let el = fixedTitlesContainer . children [ elIndex ] ;
if ( state === 'show' ) {
el . style . display = 'block' ;
setTimeout ( ( ) => {
el . style . opacity = '1' ;
} , 1 ) ;
} else if ( state === 'hide' ) {
el . style . opacity = '0' ;
setTimeout ( ( ) => {
el . style . display = 'none' ;
} , 300 ) ;
}
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// ICI IL Y A LE GRAB DU CURSEUR DE LA TL
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// make the cursor move on scroll
let cursor = document . querySelector ( '#cursor' ) ;
}
// make the cursor move on scroll
function setupCursor ( ) {
cursor . style . top = ` ${ document . querySelector ( '#timeline_container' ) . getBoundingClientRect ( ) . top } px ` ;
cursor . style . cursor = 'grab' ;
let titres = document . querySelector ( '#titres_frise' ) ;
titres . style . cursor = 'grab' ;
let partRects ;
function setPartRects ( ) {
partRects = document . querySelectorAll ( '#timeline_container div' ) ;
partRects = Array . from ( partRects ) ;
partRects = partRects . reverse ( ) ;
partRects [ 0 ] . style . width = '32px' ;
}
setPartRects ( ) ;
document . addEventListener ( "scroll" , ( ) => {
if ( ! grabbing ) {
displayCurrentPartTitle ( getCurrentPartFromScroll ( ) ) ;
if ( document . documentElement . scrollTop === 0 ) {
let firstTimeText = document . querySelector ( 'tbody tr:nth-of-type(2) td:first-of-type' ) ;
titres . firstElementChild . innerText = firstTimeText . innerText ;
} else if ( document . documentElement . scrollTop + window . innerHeight >= document . body . scrollHeight ) {
let lastTimeText = document . querySelector ( 'tbody tr:last-of-type td:first-of-type' ) ;
titres . firstElementChild . innerText = lastTimeText . innerText ;
}
moveCursorFromScroll ( getCurrentPartFromScroll ( ) ) ;
titresCursor . style . cursor = 'grab' ;
}
function setPartRects ( ) {
partRects = document . querySelectorAll ( '#timeline_container div' ) ;
partRects = Array . from ( partRects ) ;
partRects = partRects . reverse ( ) ;
partRects [ 0 ] . style . width = '32px' ;
}
document . addEventListener ( "scroll" , ( ) => {
if ( ! grabbing ) {
displayCurrentPartTitle ( getCurrentPartFromScroll ( ) ) ;
if ( document . documentElement . scrollTop === 0 ) {
let firstTimeText = document . querySelector ( 'tbody tr:nth-of-type(2) td:first-of-type' ) ;
titresCursor . firstElementChild . innerText = firstTimeText . innerText ;
} else if ( document . documentElement . scrollTop + window . innerHeight >= document . body . scrollHeight ) {
let lastTimeText = document . querySelector ( 'tbody tr:last-of-type td:first-of-type' ) ;
titresCursor . firstElementChild . innerText = lastTimeText . innerText ;
}
moveCursorFromScroll ( getCurrentPartFromScroll ( ) ) ;
}
} ) ;
function makeElementDraggable ( element , relatedEl ) {
let offsetY ;
element . addEventListener ( 'mousedown' , ( e ) => {
let elTransformY = element . style . transform ? + element . style . transform . split ( '(' ) [ 1 ] . split ( 'p' ) [ 0 ] : 0 ;
e . preventDefault ( ) ;
grabbing = true ;
offsetY = e . clientY - elTransformY ;
element . style . cursor = 'grabbing' ;
} ) ;
function makeElementDraggable ( element , relatedEl ) {
let offsetY ;
element . addEventListener ( 'mousedown' , ( e ) => {
let elTransformY ;
if ( ! element . style . transform ) {
elTransformY = 0 ;
} else {
elTransformY = + element . style . transform . split ( '(' ) [ 1 ] . split ( 'p' ) [ 0 ] ;
}
e . preventDefault ( ) ;
grabbing = true ;
offsetY = e . clientY - elTransformY ;
element . style . cursor = 'grabbing' ;
} ) ;
document . addEventListener ( 'mousemove' , ( e ) => {
if ( grabbing ) {
if ( e . clientY < tlContainerHeight + tlContainer . offsetTop && e . clientY > tlContainer . offsetTop ) {
const y = e . clientY - offsetY ;
element . style . transform = ` translateY( ${ y } px) ` ;
relatedEl . style . transform = ` translateY( ${ y } px) ` ;
if ( ! isNaN ( y ) ) displayCurrentPartTitle ( getCurrentPartFromCursor ( y ) ) ;
} else if ( e . clientY < tlContainer . offsetTop + 10 ) {
element . style . transform = ` translateY(0px) ` ;
relatedEl . style . transform = ` translateY(0px) ` ;
document . addEventListener ( 'mousemove' , ( e ) => {
if ( grabbing ) {
const y = e . clientY - offsetY ;
if ( e . clientY < tlContainerHeight + tlContainer . offsetTop && e . clientY > tlContainer . offsetTop && y > 0 ) {
element . style . transform = ` translateY( ${ y } px) ` ;
relatedEl . style . transform = ` translateY( ${ y } px) ` ;
if ( ! isNaN ( y ) ) displayCurrentPartTitle ( getCurrentPartFromCursor ( y ) ) ;
} else if ( e . clientY < tlContainer . offsetTop || y <= 0 ) {
element . style . transform = ` translateY(0px) ` ;
relatedEl . style . transform = ` translateY(0px) ` ;
setTimeout ( ( ) => {
let firstTimeText = document . querySelector ( 'tbody tr:nth-of-type(2) td:first-of-type' ) ;
titres . firstElementChild . innerText = firstTimeText . innerText ;
} else if ( e . clientY >= tlContainerHeight + tlContainer . offsetTop ) {
element . style . transform = ` translateY( ${ tlContainerHeight } px) ` ;
relatedEl . style . transform = ` translateY( ${ tlContainerHeight } px) ` ;
let lastTimeText = document . querySelector ( 'tbody tr:last-of-type td:first-of-type' ) ;
titres . firstElementChild . innerText = lastTimeText . innerText ;
}
}
} ) ;
document . addEventListener ( 'mouseup' , ( ) => {
if ( grabbing ) scrollOnGrab ( element ) ;
element . style . cursor = 'grab' ;
grabbing = false ;
} ) ;
}
makeElementDraggable ( cursor , titres ) ;
makeElementDraggable ( titres , cursor ) ;
// get heights of parts dans le tableau et dans la timeline
function getSteps ( ) {
let tlElSteps = [ ] ;
for ( let i = 0 ; i < partRects . length ; i ++ ) {
tlElSteps . push ( partRects [ i ] . offsetTop ) ;
}
let titles = document . querySelectorAll ( '.isMainPart, .isSubPart' ) ;
let scrollSteps = [ ] ;
for ( let title of titles ) {
let nextLine = title . nextElementSibling ;
if ( ! nextLine ? . classList . contains ( 'isSubPart' ) ) {
scrollSteps . push ( title . offsetTop ) ;
titresCursor . firstElementChild . innerText = firstTimeText . innerText ;
} , 100 ) ;
} else if ( e . clientY > = tlContainerHeight + tlContainer . offsetTop ) {
element . style . transform = ` translateY( ${ tlContainerHeight } px) ` ;
relatedEl . style . transform = ` translateY( ${ tlContainerHeight } px) ` ;
let lastTimeText = document . querySelector ( 'tbody tr:last-of-type td:first-of-type' ) ;
titresCursor . firstElementChild . innerText = lastTimeText . innerText ;
}
}
return ( {
'tlElSteps' : tlElSteps ,
'scrollSteps' : scrollSteps
} ) ;
}
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// ICI IL Y A LE SCROLL DU GRAB
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
let isScrollingFromGrab = false ;
function scrollOnGrab ( el ) {
let scrollValue =
( ( getSteps ( ) . scrollSteps [ getCursorPositionInTimelinePart ( el ) . stepAfterMouseUp ] - getSteps ( ) . scrollSteps [ getCursorPositionInTimelinePart ( el ) . stepAfterMouseUp - 1 ] ) * getCursorPositionInTimelinePart ( el ) . proportionInPart )
+ getSteps ( ) . scrollSteps [ getCursorPositionInTimelinePart ( el ) . stepAfterMouseUp ] ;
isScrollingFromGrab = true ;
window . scrollTo ( { top : scrollValue , behavior : 'smooth' } ) ;
setTimeout ( ( ) => {
isScrollingFromGrab = false ;
} , 2000 ) ;
}
function getCursorPositionInTimelinePart ( el ) {
let elTransformY ;
if ( ! el . style . transform ) {
elTransformY = 0 ;
} else {
elTransformY = + el . style . transform . split ( '(' ) [ 1 ] . split ( 'p' ) [ 0 ] ;
}
let tlPartHeight , tlPartBottom , tlPartTop , proportionInPart , stepAfterMouseUp ;
for ( let j = 0 ; j < partRects . length ; j ++ ) {
if ( j === getCurrentPartFromCursor ( elTransformY ) ) {
tlPartHeight = partRects [ j ] . getBoundingClientRect ( ) . height ;
tlPartBottom = partRects [ j ] . getBoundingClientRect ( ) . top - tlContainer . getBoundingClientRect ( ) . top ;
tlPartTop = tlPartBottom - tlPartHeight ;
proportionInPart = ( ( tlPartHeight - ( elTransformY - tlPartTop ) ) / tlPartHeight ) * - 1 ;
if ( proportionInPart > 0 && proportionInPart < 1 ) {
stepAfterMouseUp = j ;
return { stepAfterMouseUp , proportionInPart } ;
} else {
stepAfterMouseUp = j ;
proportionInPart = 0 ;
return { stepAfterMouseUp , proportionInPart } ;
}
}
}
}
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// ICI IL Y A LE RAPPORT SCROLL / TIMELINE
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
function moveCursorFromScroll ( currentPartIndex ) {
if ( ! isScrollingFromGrab ) {
let currentScroll = window . scrollY ;
let cursorTopValue = 0 ;
let tlPartHeight , tlPartBottom ;
for ( let j = 0 ; j < partRects . length ; j ++ ) {
tlPartHeight = partRects [ j ] . getBoundingClientRect ( ) . height
tlPartBottom = partRects [ j ] . getBoundingClientRect ( ) . top - tlContainer . getBoundingClientRect ( ) . top ;
cursorTopValue = tlPartBottom ;
// get the amount of the current scrollpart scrolled
if ( j === currentPartIndex ) break ;
}
let currentScrollPartBottom = getSteps ( ) . scrollSteps [ currentPartIndex - 1 ] ? getSteps ( ) . scrollSteps [ currentPartIndex - 1 ] : 0 ;
let currentScrollPartHeight ;
if ( getSteps ( ) . scrollSteps [ currentPartIndex + 1 ] ) {
currentScrollPartHeight = getSteps ( ) . scrollSteps [ currentPartIndex + 1 ] - currentScrollPartBottom ;
} ) ;
document . addEventListener ( 'mouseup' , ( e ) => {
if ( grabbing ) {
scrollOnGrab ( element ) ;
let elTransformY = element . style . transform ? + element . style . transform . split ( '(' ) [ 1 ] . split ( 'p' ) [ 0 ] : 0 ;
offsetY = e . clientY - elTransformY ;
const y = e . clientY - offsetY ;
if ( e . clientY < tlContainer . offsetTop || y <= 0 ) {
window . scrollTo ( 0 , 0 ) ;
} else {
currentScrollPartHeight = document . querySelector ( 'body' ) . scrollHeight - currentScrollPartBottom ;
}
let currentScrollSincePartBottom = currentScroll - currentScrollPartBottom ;
let scrollPartProportion = currentScrollSincePartBottom / currentScrollPartHeight ;
cursorTopValue = cursorTopValue + tlPartHeight * ( tlPartHeight / tlPartHeight * ( scrollPartProportion - 0.3 ) ) ;
if ( cursorTopValue > 0 ) {
cursor . style . transform = ` translateY( ${ cursorTopValue } px) ` ;
titres . style . transform = ` translateY( ${ cursorTopValue } px) ` ;
} else {
cursor . style . transform = ` translateY(0px) ` ;
titres . style . transform = ` translateY(0px) ` ;
setTimeout ( ( ) => {
titresCursor . firstElementChild . innerText = getCurrentTime ( titresFrise [ getCurrentPartFromCursor ( y ) ] ? . el ) ;
} , 1000 ) ;
}
}
element . style . cursor = 'grab' ;
grabbing = false ;
} ) ;
}
// get heights of parts dans le tableau et dans la timeline
function getSteps ( ) {
steps . tlElSteps = [ ] ;
steps . scrollSteps = [ ] ;
for ( let i = 0 ; i < partRects . length ; i ++ ) {
// steps.tlElSteps.push(partRects[i].offsetTop);
steps . tlElSteps . push ( partRects [ i ] . getBoundingClientRect ( ) . top ) ;
}
let prevPartIndex = 0 ;
let lastCallTimestamp = 0 ;
function displayCurrentPartTitle ( currentPartIndex ) {
if ( isNaN ( currentPartIndex ) ) currentPartIndex = 0 ;
const currentTime = performance . now ( ) ;
if ( currentTime - lastCallTimestamp >= 400 ) {
lastCallTimestamp = currentTime ;
titres . firstElementChild . innerText = getCurrentTime ( titresFrise [ currentPartIndex ] ? . el ) ; // ICI POUR METTRE LE TEMPS BIEN
setTimeout ( ( ) => {
if ( isWindowScrolling ( ) ) {
setTimeout ( ( ) => {
titres . firstElementChild . innerText = getCurrentTime ( titresFrise [ currentPartIndex ] ? . el ) ;
} , 400 ) ;
}
} , 200 ) ;
let titles = document . querySelectorAll ( '.isMainPart, .isSubPart' ) ;
for ( let title of titles ) {
let nextLine = title . nextElementSibling ;
if ( ! nextLine ? . classList . contains ( 'isSubPart' ) ) {
// steps.scrollSteps.push(title.offsetTop);
steps . scrollSteps . push ( title . offsetTop ) ;
}
let mainEl = titres . children [ 1 ] ;
let subEl = titres . lastElementChild ;
if ( mainEl . innerText != titresFrise [ currentPartIndex ] ? . main || subEl . innerText != titresFrise [ currentPartIndex ] ? . sub ) {
mainEl . innerText = titresFrise [ currentPartIndex ] ? . main ;
subEl . innerText = titresFrise [ currentPartIndex ] ? . sub ;
partRects [ prevPartIndex ] . style . width = '22px' ;
partRects [ currentPartIndex ] . style . width = '32px' ;
}
activePartIndex = currentPartIndex ;
prevPartIndex = currentPartIndex ;
}
function getCurrentPartFromScroll ( ) {
}
function scrollOnGrab ( el ) {
let scrollValue ;
if ( getCursorPositionInTimelinePart ( el ) . stepAfterMouseUp === steps . scrollSteps . length - 1 ) {
scrollValue =
( ( document . documentElement . scrollHeight - steps . scrollSteps [ getCursorPositionInTimelinePart ( el ) . stepAfterMouseUp ] ) * getCursorPositionInTimelinePart ( el ) . proportionInPart )
+ steps . scrollSteps [ getCursorPositionInTimelinePart ( el ) . stepAfterMouseUp ] ;
} else {
scrollValue =
( ( steps . scrollSteps [ getCursorPositionInTimelinePart ( el ) . stepAfterMouseUp + 1 ] - steps . scrollSteps [ getCursorPositionInTimelinePart ( el ) . stepAfterMouseUp ] ) * getCursorPositionInTimelinePart ( el ) . proportionInPart )
+ steps . scrollSteps [ getCursorPositionInTimelinePart ( el ) . stepAfterMouseUp ] ;
}
isScrollingFromGrab = true ;
window . scrollTo ( { top : scrollValue , behavior : 'smooth' } ) ;
setTimeout ( ( ) => {
isScrollingFromGrab = false ;
} , 1000 ) ;
}
function getCursorPositionInTimelinePart ( el ) {
let elTransformY ;
if ( ! el . style . transform ) {
elTransformY = 0 ;
} else {
elTransformY = + el . style . transform . split ( '(' ) [ 1 ] . split ( 'p' ) [ 0 ] ;
}
let tlPartHeight , tlPartBottom , tlPartTop , proportionInPart , stepAfterMouseUp ;
tlPartHeight = partRects [ getCurrentPartFromCursor ( elTransformY ) || 0 ] . getBoundingClientRect ( ) . height ;
tlPartBottom = partRects [ getCurrentPartFromCursor ( elTransformY ) || 0 ] . getBoundingClientRect ( ) . bottom - tlContainer . getBoundingClientRect ( ) . top ;
tlPartTop = steps . tlElSteps [ getCurrentPartFromCursor ( elTransformY ) || 0 ] - steps . tlElSteps [ 0 ] ;
proportionInPart = 1 - ( ( tlPartHeight - ( elTransformY - tlPartTop ) ) / tlPartHeight ) ;
if ( proportionInPart > 0 && proportionInPart < 1 ) {
stepAfterMouseUp = getCurrentPartFromCursor ( elTransformY ) ;
return { stepAfterMouseUp , proportionInPart } ;
} else {
stepAfterMouseUp = getCurrentPartFromCursor ( elTransformY ) ;
proportionInPart = 0 ;
return { stepAfterMouseUp , proportionInPart } ;
}
}
function moveCursorFromScroll ( currentPartIndex ) {
if ( ! isScrollingFromGrab ) {
let currentScroll = window . scrollY ;
for ( let i = 0 ; i < getSteps ( ) . scrollSteps . length ; i ++ ) {
if (
( currentScroll + window . innerHeight / 2 >= getSteps ( ) . scrollSteps [ i ]
&& currentScroll + window . innerHeight / 2 < = getSteps ( ) . scrollSteps [ i + 1 ] ) ||
( currentScroll + window . innerHeight / 2 >= getSteps ( ) . scrollSteps [ i ]
&& i === getSteps ( ) . scrollSteps . length - 1 )
) {
return ( i ) ;
}
}
}
function getCurrentPartFromCursor ( cursorTransformY ) {
for ( let i = 0 ; i < getSteps ( ) . tlElSteps . length ; i ++ ) {
if ( cursorTransformY >= getSteps ( ) . tlElSteps [ i ] && cursorTransformY < getSteps ( ) . tlElSteps [ i + 1 ] ) {
return ( i ) ;
} else if ( cursorTransformY > getSteps ( ) . tlElSteps [ getSteps ( ) . tlElSteps . length - 1 ] ) {
return ( getSteps ( ) . tlElSteps . length - 1 ) ;
}
}
}
///////////////////////////////////////
// ICI LE GETCURRENTTIME !!!!!!!!!!!!!!
///////////////////////////////////////
function getCurrentTime ( titleEl ) {
let nextRow = titleEl ? . nextElementSibling ;
if ( ! grabbing ) {
while ( nextRow ) {
if ( nextRow . offsetTop - window . innerHeight / 4 > window . scrollY &&
nextRow . classList . contains ( 'isContentPart' ) ) {
return ( nextRow . firstElementChild . innerText ) ;
}
nextRow = nextRow . nextElementSibling ;
}
let tlPartHeight = parseInt ( partRects [ currentPartIndex ] . style . height ) ;
let cursorTopValue = partRects [ currentPartIndex ] . getBoundingClientRect ( ) . top - parseInt ( tlContainer . style . top ) ;
let currentScrollPartTop = steps . scrollSteps [ currentPartIndex ] || 0 ;
let currentScrollPartHeight ;
if ( steps . scrollSteps [ currentPartIndex + 1 ] ) {
currentScrollPartHeight = steps . scrollSteps [ currentPartIndex + 1 ] - currentScrollPartTop ;
} else {
let cursor = document . querySelector ( '#cursor' ) ;
let allRowsUnder = [ ] ;
nextRow = nextRow . nextElementSibling . nextElementSibling ;
while ( nextRow ) {
if ( nextRow . classList . contains ( 'isMainPart' ) || nextRow . classList . contains ( 'isSubPart' ) ) {
break ;
}
allRowsUnder . push ( nextRow ) ;
nextRow = nextRow . nextElementSibling ;
}
let currentRowIndex = Math . floor ( allRowsUnder . length * getCursorPositionInTimelinePart ( cursor ) . proportionInPart ) ;
if ( currentRowIndex - 20 >= 0 ) {
return allRowsUnder [ currentRowIndex - 20 ] . firstElementChild . innerText ;
} else {
return allRowsUnder [ 0 ] . firstElementChild . innerText ;
}
currentScrollPartHeight = document . querySelector ( 'body' ) . scrollHeight - currentScrollPartTop ;
}
let currentScrollSincePartBottom = currentScroll - currentScrollPartTop ;
let scrollPartProportion = currentScrollSincePartBottom / currentScrollPartHeight ;
cursorTopValue = cursorTopValue + tlPartHeight * scrollPartProportion ;
if ( cursorTopValue > 0 ) {
cursor . style . transform = ` translateY( ${ cursorTopValue } px) ` ;
titresCursor . style . transform = ` translateY( ${ cursorTopValue } px) ` ;
} else {
cursor . style . transform = ` translateY(0px) ` ;
titresCursor . style . transform = ` translateY(0px) ` ;
}
}
}
function displayCurrentPartTitle ( currentPartIndex ) {
if ( isNaN ( currentPartIndex ) ) currentPartIndex = 0 ;
const currentTime = performance . now ( ) ;
if ( currentTime - lastCallTimestamp >= timestampDebounce ) {
lastCallTimestamp = currentTime ;
if ( titresCursor ) titresCursor . firstElementChild . innerText = getCurrentTime ( titresFrise [ currentPartIndex ] ? . el ) ; // ICI POUR METTRE LE TEMPS BIEN
}
let mainEl = titresCursor . children [ 1 ] ;
let subEl = titresCursor . lastElementChild ;
if ( mainEl . innerText != titresFrise [ currentPartIndex ] ? . main || subEl . innerText != titresFrise [ currentPartIndex ] ? . sub ) {
mainEl . innerText = titresFrise [ currentPartIndex ] ? . main ;
subEl . innerText = titresFrise [ currentPartIndex ] ? . sub ;
partRects [ prevPartIndex ] . style . width = '22px' ;
partRects [ currentPartIndex ] . style . width = '32px' ;
}
activePartIndex = currentPartIndex ;
prevPartIndex = currentPartIndex ;
}
function getCurrentPartFromScroll ( ) {
let currentScroll = window . scrollY ;
for ( let i = 0 ; i < steps . scrollSteps . length ; i ++ ) {
if (
( currentScroll + window . innerHeight / 2 >= steps . scrollSteps [ i ]
&& currentScroll + window . innerHeight / 2 <= steps . scrollSteps [ i + 1 ] ) ||
( currentScroll + window . innerHeight / 2 >= steps . scrollSteps [ i ]
&& i === steps . scrollSteps . length - 1 )
) {
return ( i ) ;
}
}
}
function getCurrentPartFromCursor ( cursorTransformY ) {
for ( let i = 0 ; i < steps . tlElSteps . length ; i ++ ) {
if ( cursorTransformY >= steps . tlElSteps [ i ] - steps . tlElSteps [ 0 ] && cursorTransformY < steps . tlElSteps [ i + 1 ] - steps . tlElSteps [ 0 ] ) {
return ( i ) ;
} else if ( cursorTransformY > steps . tlElSteps [ steps . tlElSteps . length - 1 ] - steps . tlElSteps [ 0 ] ) {
return ( steps . tlElSteps . length - 1 ) ;
}
}
}
function getCurrentTime ( titleEl ) {
let nextRow = titleEl ? . nextElementSibling ;
let allRowsUnder = [ ] ;
if ( ! grabbing ) {
while ( nextRow ) {
if ( nextRow . offsetTop - window . innerHeight / 4 > window . scrollY &&
nextRow . classList . contains ( 'isContentPart' ) ) {
return nextRow . firstElementChild . innerText ;
}
allRowsUnder . push ( nextRow . firstElementChild . innerText ) ;
nextRow = nextRow . nextElementSibling ;
}
return allRowsUnder [ allRowsUnder . length - 1 ] ;
} else {
let cursor = document . querySelector ( '#cursor' ) ;
if ( nextRow . classList . contains ( 'isSubPart' ) ) nextRow = nextRow . nextElementSibling . nextElementSibling ;
while ( nextRow ) {
if ( nextRow . classList . contains ( 'isMainPart' ) || nextRow . classList . contains ( 'isSubPart' ) ) {
break ;
}
allRowsUnder . push ( nextRow . firstElementChild . innerText ) ;
nextRow = nextRow . nextElementSibling ;
}
let currentRowIndex = Math . floor ( allRowsUnder . length * getCursorPositionInTimelinePart ( cursor ) . proportionInPart ) ;
return allRowsUnder [ currentRowIndex ] ;
}
}
setPartTitlesInPartition ( ) ;
setPartsColors ( ) ;
getPartsTimes ( ) ;
setTimeout ( ( ) => {
getAllHeights ( ) ;
drawFriseRects ( ) ;
displayTimelineTitles ( ) ;
setupCursor ( ) ;
drawFixedTitles ( ) ;
setPartRects ( ) ;
makeElementDraggable ( cursor , titresCursor ) ;
makeElementDraggable ( titresCursor , cursor ) ;
getSteps ( ) ;
} , 100 ) ;
let resizeTimeout ;
window . addEventListener ( 'resize' , ( ) => {
tlContainer . innerHTML = '' ;
document . querySelector ( "#titres_frise" ) ? . remove ( ) ;
clearTimeout ( resizeTimeout ) ;
resizeTimeout = setTimeout ( ( ) => {
getAllHeights ( ) ;
drawFriseRects ( ) ;
displayTimelineTitles ( ) ;
setupCursor ( ) ;
setPartRects ( ) ;
makeElementDraggable ( titresCursor , cursor ) ;
getSteps ( ) ;
} , 100 ) ;
} ) ;
}
export { customTimeline } ;