Tuesday, 30 April 2019

Buggy slider - how make my slider well fit the component inside?

I would create a slider like the MacDonalds one:

the objective is that my slider fit the contained element, then when I click the right or left button that my slider go on one side or another, and come back to other boundary if the user has reached one or other boundary side.

The problem is that my slider is fully inconsistent, it doesn't responses to the event triggering correctly and the management of the state seems very buggy also, so I m wondering how to improve my application,

My slider fails to have a fluent behavior, here the demo -beware the script bugs on my browser using StackOverflow but JSFiddle succeeds to read the script well:

let scopeProps= 5 

class App extends React.Component{

  state={
    // number of items in he slider
    totalSliderItem:0,
    // deplacement range to handle the sliding => default to scopeProps
    moveRange: scopeProps,
    // range of sliderView => default to scopeProps
    boxScope:scopeProps,

    // unitWidth of each box item => scopeProps/ number of item desired inside a box view
    unitWidth:0,

    // number of item outside box view localize at the right of box
    outsideBoxRight:0,
    // number of item outside box view localize at the left of box
    outsideBoxLeft:0


  } 

  componentDidMount(){
    // set CSS variable 
    // § call body variable     
    let root= document.body;

    // § update css variable --slider-container-scope
    root.style.setProperty('--slider-container-scope', scopeProps);
   
    // § update css variable CSS variable --unit-width
    // call metacontainer ref
    let SliderMetaContainer= this.refs.sliderMetaContainer
    // get metacontainer width
    let metaContainerWidth=SliderMetaContainer.getBoundingClientRect().width
    let unitWidth= metaContainerWidth/scopeProps
    root.style.setProperty('--unit-width', unitWidth + "px") ;

    // set number of items contained in slider
    let sliderContainer= this.refs.sliderContainer
    let sliderContainerLength= sliderContainer.childElementCount
    console.log("sliderContainerRef length: ", sliderContainerLength);

    // initial number of items localized outside box view == all box overcosm slider scope
    let outsideBoxRight=sliderContainerLength-scopeProps

    // initialize state after componentDidMount
    this.setState({
      totalSliderItem:sliderContainerLength,
      outsideBoxRight,
      unitWidth
    })
  }

  // when user click a button to move => handleSlideMove()
  handleSlideMove=(direction)=>{
    console.log("window: ", window)

  
    console.log("in handleSlideMove")

    // appreciate number of item outsideBox depending of direction targeted
    let outsideBoxUnit= direction==="left" ? -(this.state["outsideBoxLeft"]) : this.state["outsideBoxRight"];

    // direction => if(outsideBox(direction)<=0 ==> call boundary 
    if(outsideBoxUnit <= 0){ 
        // go to other boundary  
        let boundaryRange = this.state.totalSliderItem - this.state.boxScope; 
        this.boundaryMove(boundaryRange, direction)
    }
    // else make a move further in the slider
    else this.furtherMove(outsideBoxUnit, direction)
  }

    boundaryMove=(boundaryRange, direction)=>{
      console.log("in boundaryMove")
      // each category has a specific unitWidth
      let unitWidth=this.state.unitWidth 
      let boxScope=this.state.boxScope

      // set other boundary range
      let moveRange= boundaryRange
      let move=   unitWidth * moveRange
      // console.log("unitWidth, boxScope, outsideBoxUnit: ", unitWidth, boxScope, outsideBoxUnit);

      // set movement range
      // let move= outsideBoxUnit < boxScope?   unitWidth * outsideBoxUnit: unitWidth * boxScope  
      
      // console.log("move: ", move);

      // handle movement direction
      if(direction==="left") move= -move 

      console.log("move value: ", move)
      // trigger movement
      document.body.style.setProperty('--item-left', move + "px");  

      this.updateItemRepartition(moveRange)
    }

    furtherMove=(outsideBoxUnit, direction)=>{
      console.log("in furtherMove")
      // each category has a specific unitWidth
      let unitWidth=this.state.unitWidth 
      console.log("line 109, unitWidth: ", unitWidth)

      let boxScope=this.state.boxScope    
      let move  
      


      let moveRange = outsideBoxUnit < boxScope?    outsideBoxUnit: boxScope
      // handle movement direction
      move=   unitWidth * moveRange   

      // if(direction==="left") move=move      


      console.log("outsideBoxUnit line 104: ", outsideBoxUnit)
      console.log("move value: ", move)
      // trigger movement
      document.body.style.setProperty('--item-left', move + "px");

      this.updateItemRepartition(moveRange, direction)
    }

  // update how many items are outside the box view from each side
  updateItemRepartition=(moveRange, direction)=>{ 
    // get boxScope
    let boxScope=this.state.boxScope 
    // appreciate if the number to use for update should be boxScope _ outsideBox
    let range= moveRange < boxScope? moveRange : boxScope

    // update outsideBox value according to movement direction
    this.setState( currentState =>{ 
        // move to left => increase right outsideBoxItem _ decrease left outsideBoxItem
        let updateBoxRight= direction === "left" ?  
            currentState.outsideBoxRight + range
                :
            currentState.outsideBoxRight - range
        // move to righ => increase left outsideBoxItem _ decrease right outsideBoxItem
        let updateBoxLeft= direction !== "left" ?  
            currentState.outsideBoxLeft + range
                :
            currentState.outsideBoxLeft - range

        // debugging => appreciate number to evaluate if update would be relevant
        console.log(
            "currentState.outsideBoxLeft, currentState.outsideBoxRight, range: ",
            currentState.outsideBoxLeft, currentState.outsideBoxRight, range
        )

        // update component state
        return ({
            outsideBoxRight:updateBoxRight,
            outsideBoxLeft:updateBoxLeft
        })
    })
  }


  render(){

    return (
      <div className="page">
        Awesome containers here! 

        <button onClick={() => this.handleSlideMove("left")} > 
          move left
        </button>

        <div ref="sliderMetaContainer" className="slider_metacontainer"> 
          <div ref="sliderContainer" className="slider_container"> 
            <div className="slider_item"> 
              1
            </div>
            <div className="slider_item"> 
              2
            </div>
            <div className="slider_item"> 
              3
            </div>
            <div className="slider_item"> 
              4
            </div>
            <div className="slider_item"> 
              5
            </div>
            <div className="slider_item"> 
              6
            </div>
            <div className="slider_item"> 
              7
            </div>
            <div className="slider_item"> 
              8
            </div>
            <div className="slider_item"> 
              9
            </div>
            <div className="slider_item"> 
              10
            </div>
             <div className="slider_item"> 
              11
            </div>
            <div className="slider_item"> 
              12
            </div>
            <div className="slider_item"> 
              13
            </div>
            <div className="slider_item"> 
              14
            </div>
            <div className="slider_item"> 
              15
            </div> 
          </div>
        </div>

        <button onClick={() => this.handleSlideMove("right")} > 
          move right
        </button>
      </div>
    )
  };
}
ReactDOM.render(<App />, document.querySelector("#app"))
:root{
  --slider-container-scope: 0; 
  --unit-width: 0;
  --item-left:0;
}

.page {
  text-align: center; 
  display:flex; 
  width:100%;
  flex-direction: column;
  align-items:center;
  justify-content: center;
}  

.slider_metacontainer{
  width: 400px;

  background: #444;
  
  display: flex;
  overflow: auto;
  margin: 10vh 0;
}

.slider_container{
  position:relative; 
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: nowrap;

  left:var(--item-left);
  transition: left 0.5s ease-out;
}

.slider_item{
  width: var(--unit-width);
  height:25vh;
}

.slider_item:nth-child(3n-2) { background-color: #EF5350; }
.slider_item:nth-child(3n-1) { background-color: #2E7D32; }
.slider_item:nth-child(3n) { background-color: #03A9A4; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="app"></div>

Any hint to understand how to handle my slider would be great, Thanks!!



from Buggy slider - how make my slider well fit the component inside?

No comments:

Post a Comment