2017-09-17 3 views
0

J'essaie de déplacer la caméra autour de ma scène JSON en utilisant uniquement les mouvements de la souris. Cependant, je veux que l'appareil photo bouge avec seulement le mouvement de la souris et dans le sens de la souris sans devoir cliquer et glisser.TROIS.js Déplacez la caméra avec la souris avec des limitations

J'ai développé une version partiellement fonctionnelle de ce produit, mais ce n'est pas ce dont j'ai besoin. Je suis également à la recherche de la caméra pour arrêter de bouger à un certain point, en plus de la caméra ne changeant pas la distance entre elle-même et le JSON animé.

Voici mon code:

<!DOCTYPE html> 
<html lang="en"> 
    <head> 
     <title>three.js webgl - animation - keyframes - json</title> 
     <meta charset="utf-8"> 
     <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0"> 
     <style> 

      body { 
       color: #fff; 
       font-family:Monospace; 
       font-size:13px; 
       text-align:center; 
       background-color: #fff; 
       margin: 0px; 
       overflow: hidden; 
      } 

      #info { 
       position: absolute; 
       top: 0px; width: 100%; 
       padding: 5px; 
      } 

      a { 
       color: #2983ff; 
      } 

     </style> 
    </head> 

    <body> 

     <div id="container"></div> 

     <div id="info"> 
      <a href="http://threejs.org" target="_blank" rel="noopener">three.js</a> webgl - animation - keyframes - json 
     </div> 

     <script src="three.min.js"></script> 

     <script src="Detector.js"></script> 
     <script src="stats.min.js"></script> 

     <script> 

      var mouseX = 0, mouseY = 0; 
      var windowHalfX = window.innerWidth/2; 
      var windowHalfY = window.innerHeight/2; 


      var scene, camera, pointLight, stats; 
      var model; 
      var renderer, mixer, animationClip; 

      var clock = new THREE.Clock(); 
      var container = document.getElementById('container'); 

      stats = new Stats(); 
      container.appendChild(stats.dom); 

      renderer = new THREE.WebGLRenderer({ antialias: true }); 
      renderer.setPixelRatio(window.devicePixelRatio); 
      renderer.setSize(window.innerWidth, window.innerHeight); 
      container.appendChild(renderer.domElement); 

      document.addEventListener('mousemove', onDocumentMouseMove, false); 

      window.addEventListener('resize', onresize, false); 

      scene = new THREE.Scene(); 

      var grid = new THREE.GridHelper(20, 20, 0x888888, 0x888888); 
      grid.position.set(0, - 1.1, 0); 
      scene.add(grid); 

      camera = new THREE.PerspectiveCamera(70, window.innerWidth/window.innerHeight, 1, 1000); 
      camera.position.z = 30; 
      camera.position.y = 30; 
      // camera.position.x = 0; 
      // camera.position.set(- 5.00, 3.43, 11.31); 
      // camera.lookAt(new THREE.Vector3(- 1.22, 2.18, 4.58)); 

      scene.add(new THREE.AmbientLight(0x404040)); 

      pointLight = new THREE.PointLight(0xffffff, 1); 
      pointLight.position.copy(camera.position); 
      scene.add(pointLight); 

      new THREE.ObjectLoader().load('FuckIt2.json', function (model) { 

       scene.add(model); 

       mixer = new THREE.AnimationMixer(model); 
       mixer.clipAction(model.animations[ 0 ]).play(); 
       // 
       // model.position.y = 0; 
       // model.position.x = 0; 

       animate(); 

      }); 

      function onDocumentMouseMove(event) { 

       mouseY = (event.clientY - windowHalfX)/5; 
       mouseX = (event.clientX - windowHalfY)/5; 

      } 



      window.onresize = function() { 

       windowHalfX = window.innerWidth/1; 
       windowHalfY = window.innerHeight/1; 

       camera.aspect = window.innerWidth/window.innerHeight; 
       camera.updateProjectionMatrix(); 

       renderer.setSize(window.innerWidth, window.innerHeight); 

      }; 


      function animate() { 

       requestAnimationFrame(animate); 

       mixer.update(clock.getDelta()); 

       stats.update(); 

       render(); 
      } 

      function render() { 

       camera.position.x += (mouseX - camera.position.x) * 0.003; 
       camera.position.y += (- mouseY - camera.position.y) * 0.003; 
       camera.lookAt(scene.position); 
       renderer.render(scene, camera); 

} 
     </script> 

    </body> 
    </html> 

S'il vous plaît laissez-moi savoir ce que je peux faire pour changer cela! Toute aide est appréciée. Je vous remercie!

Répondre

0

Pourquoi réinventer la roue? Je voudrais simplement réutiliser le code TrackballControls.js et le modifier comme vous voulez, si vous ne voulez pas avoir à appuyer sur la souris pour faire tourner la caméra, puis modifier le comportement de gestion des événements et activer le mode de rotation par défaut, comme je l'ai fait ceci - sale - codepen.

/** 
* @author Eberhard Graether/http://egraether.com/ 
* @author Mark Lundin/http://mark-lundin.com 
* @author Simone Manini/http://daron1337.github.io 
* @author Luca Antiga/http://lantiga.github.io 
*/ 

THREE.MyTrackballControls = function (object, domElement) { 

    var _this = this; 
    var STATE = { NONE: - 1, ROTATE: 0, ZOOM: 1, PAN: 2, TOUCH_ROTATE: 3, TOUCH_ZOOM_PAN: 4 }; 

    this.object = object; 
    this.domElement = (domElement !== undefined) ? domElement : document; 

    // API 

    this.enabled = true; 

    this.screen = { left: 0, top: 0, width: 0, height: 0 }; 

    this.rotateSpeed = 1.0; 
    this.zoomSpeed = 1.2; 
    this.panSpeed = 0.3; 

    this.noRotate = false; 
    this.noZoom = false; 
    this.noPan = false; 

    this.staticMoving = false; 
    this.dynamicDampingFactor = 0.2; 

    this.minDistance = 0; 
    this.maxDistance = Infinity; 

    this.keys = [ 65 /*A*/, 83 /*S*/, 68 /*D*/ ]; 

    // internals 

    this.target = new THREE.Vector3(); 

    var EPS = 0.000001; 

    var lastPosition = new THREE.Vector3(); 

    var _state = STATE.ROTATE, 
    _prevState = STATE.NONE, 


    _eye = new THREE.Vector3(), 

    _movePrev = new THREE.Vector2(), 
    _moveCurr = new THREE.Vector2(), 

    _lastAxis = new THREE.Vector3(), 
    _lastAngle = 0, 

    _zoomStart = new THREE.Vector2(), 
    _zoomEnd = new THREE.Vector2(), 

    _touchZoomDistanceStart = 0, 
    _touchZoomDistanceEnd = 0, 

    _panStart = new THREE.Vector2(), 
    _panEnd = new THREE.Vector2(); 

    // for reset 

    this.target0 = this.target.clone(); 
    this.position0 = this.object.position.clone(); 
    this.up0 = this.object.up.clone(); 

    // events 

    var changeEvent = { type: 'change' }; 
    var startEvent = { type: 'start' }; 
    var endEvent = { type: 'end' }; 


    // methods 

    this.handleResize = function() { 

    if (this.domElement === document) { 

     this.screen.left = 0; 
     this.screen.top = 0; 
     this.screen.width = window.innerWidth; 
     this.screen.height = window.innerHeight; 

    } else { 

     var box = this.domElement.getBoundingClientRect(); 
     // adjustments come from similar code in the jquery offset() function 
     var d = this.domElement.ownerDocument.documentElement; 
     this.screen.left = box.left + window.pageXOffset - d.clientLeft; 
     this.screen.top = box.top + window.pageYOffset - d.clientTop; 
     this.screen.width = box.width; 
     this.screen.height = box.height; 

    } 

    }; 

    this.handleEvent = function (event) { 

    if (typeof this[ event.type ] == 'function') { 

     this[ event.type ](event); 

    } 

    }; 

    var getMouseOnScreen = (function() { 

    var vector = new THREE.Vector2(); 

    return function getMouseOnScreen(pageX, pageY) { 

     vector.set(
     (pageX - _this.screen.left)/_this.screen.width, 
     (pageY - _this.screen.top)/_this.screen.height 
    ); 

     return vector; 

    }; 

    }()); 

    var getMouseOnCircle = (function() { 

    var vector = new THREE.Vector2(); 

    return function getMouseOnCircle(pageX, pageY) { 

     vector.set(
     ((pageX - _this.screen.width * 0.5 - _this.screen.left)/(_this.screen.width * 0.5)), 
     ((_this.screen.height + 2 * (_this.screen.top - pageY))/_this.screen.width) // screen.width intentional 
    ); 

     return vector; 

    }; 

    }()); 

    this.rotateCamera = (function() { 

    var axis = new THREE.Vector3(), 
     quaternion = new THREE.Quaternion(), 
     eyeDirection = new THREE.Vector3(), 
     objectUpDirection = new THREE.Vector3(), 
     objectSidewaysDirection = new THREE.Vector3(), 
     moveDirection = new THREE.Vector3(), 
     angle; 

    return function rotateCamera() { 

     moveDirection.set(_moveCurr.x - _movePrev.x, _moveCurr.y - _movePrev.y, 0); 
     angle = moveDirection.length(); 

     if (angle) { 

     _eye.copy(_this.object.position).sub(_this.target); 

     eyeDirection.copy(_eye).normalize(); 
     objectUpDirection.copy(_this.object.up).normalize(); 
     objectSidewaysDirection.crossVectors(objectUpDirection, eyeDirection).normalize(); 

     objectUpDirection.setLength(_moveCurr.y - _movePrev.y); 
     objectSidewaysDirection.setLength(_moveCurr.x - _movePrev.x); 

     moveDirection.copy(objectUpDirection.add(objectSidewaysDirection)); 

     axis.crossVectors(moveDirection, _eye).normalize(); 

     angle *= _this.rotateSpeed; 
     quaternion.setFromAxisAngle(axis, angle); 

     _eye.applyQuaternion(quaternion); 
     _this.object.up.applyQuaternion(quaternion); 

     _lastAxis.copy(axis); 
     _lastAngle = angle; 

     } else if (! _this.staticMoving && _lastAngle) { 

     _lastAngle *= Math.sqrt(1.0 - _this.dynamicDampingFactor); 
     _eye.copy(_this.object.position).sub(_this.target); 
     quaternion.setFromAxisAngle(_lastAxis, _lastAngle); 
     _eye.applyQuaternion(quaternion); 
     _this.object.up.applyQuaternion(quaternion); 

     } 

     _movePrev.copy(_moveCurr); 

    }; 

    }()); 


    this.zoomCamera = function() { 

    var factor; 

    if (_state === STATE.TOUCH_ZOOM_PAN) { 

     factor = _touchZoomDistanceStart/_touchZoomDistanceEnd; 
     _touchZoomDistanceStart = _touchZoomDistanceEnd; 
     _eye.multiplyScalar(factor); 

    } else { 

     factor = 1.0 + (_zoomEnd.y - _zoomStart.y) * _this.zoomSpeed; 

     if (factor !== 1.0 && factor > 0.0) { 

     _eye.multiplyScalar(factor); 

     } 

     if (_this.staticMoving) { 

     _zoomStart.copy(_zoomEnd); 

     } else { 

     _zoomStart.y += (_zoomEnd.y - _zoomStart.y) * this.dynamicDampingFactor; 

     } 

    } 

    }; 

    this.panCamera = (function() { 

    var mouseChange = new THREE.Vector2(), 
     objectUp = new THREE.Vector3(), 
     pan = new THREE.Vector3(); 

    return function panCamera() { 

     mouseChange.copy(_panEnd).sub(_panStart); 

     if (mouseChange.lengthSq()) { 

     mouseChange.multiplyScalar(_eye.length() * _this.panSpeed); 

     pan.copy(_eye).cross(_this.object.up).setLength(mouseChange.x); 
     pan.add(objectUp.copy(_this.object.up).setLength(mouseChange.y)); 

     _this.object.position.add(pan); 
     _this.target.add(pan); 

     if (_this.staticMoving) { 

      _panStart.copy(_panEnd); 

     } else { 

      _panStart.add(mouseChange.subVectors(_panEnd, _panStart).multiplyScalar(_this.dynamicDampingFactor)); 

     } 

     } 

    }; 

    }()); 

    this.checkDistances = function() { 

    if (! _this.noZoom || ! _this.noPan) { 

     if (_eye.lengthSq() > _this.maxDistance * _this.maxDistance) { 

     _this.object.position.addVectors(_this.target, _eye.setLength(_this.maxDistance)); 
     _zoomStart.copy(_zoomEnd); 

     } 

     if (_eye.lengthSq() < _this.minDistance * _this.minDistance) { 

     _this.object.position.addVectors(_this.target, _eye.setLength(_this.minDistance)); 
     _zoomStart.copy(_zoomEnd); 

     } 

    } 

    }; 

    this.update = function() { 

    _eye.subVectors(_this.object.position, _this.target); 

    if (! _this.noRotate) { 

     _this.rotateCamera(); 

    } 

    if (! _this.noZoom) { 

     _this.zoomCamera(); 

    } 

    if (! _this.noPan) { 

     _this.panCamera(); 

    } 

    _this.object.position.addVectors(_this.target, _eye); 

    _this.checkDistances(); 

    _this.object.lookAt(_this.target); 

    if (lastPosition.distanceToSquared(_this.object.position) > EPS) { 

     _this.dispatchEvent(changeEvent); 

     lastPosition.copy(_this.object.position); 

    } 

    }; 

    this.reset = function() { 

    _state = STATE.NONE; 
    _prevState = STATE.NONE; 

    _this.target.copy(_this.target0); 
    _this.object.position.copy(_this.position0); 
    _this.object.up.copy(_this.up0); 

    _eye.subVectors(_this.object.position, _this.target); 

    _this.object.lookAt(_this.target); 

    _this.dispatchEvent(changeEvent); 

    lastPosition.copy(_this.object.position); 

    }; 

    // listeners 

    function keydown(event) { 

    if (_this.enabled === false) return; 

    window.removeEventListener('keydown', keydown); 

    _prevState = _state; 

    if (_state !== STATE.NONE) { 

     return; 

    } else if (event.keyCode === _this.keys[ STATE.ROTATE ] && ! _this.noRotate) { 

     _state = STATE.ROTATE; 

    } else if (event.keyCode === _this.keys[ STATE.ZOOM ] && ! _this.noZoom) { 

     _state = STATE.ZOOM; 

    } else if (event.keyCode === _this.keys[ STATE.PAN ] && ! _this.noPan) { 

     _state = STATE.PAN; 

    } 

    } 

    function keyup(event) { 

    if (_this.enabled === false) return; 

    _state = _prevState; 

    window.addEventListener('keydown', keydown, false); 

    } 

    function mousedown(event) { 

    if (_this.enabled === false) return; 

    event.preventDefault(); 
    event.stopPropagation(); 

    if (_state === STATE.NONE) { 

     _state = event.button; 

    } 

    if (_state === STATE.ROTATE && ! _this.noRotate) { 

     _moveCurr.copy(getMouseOnCircle(event.pageX, event.pageY)); 
     _movePrev.copy(_moveCurr); 

    } else if (_state === STATE.ZOOM && ! _this.noZoom) { 

     _zoomStart.copy(getMouseOnScreen(event.pageX, event.pageY)); 
     _zoomEnd.copy(_zoomStart); 

    } else if (_state === STATE.PAN && ! _this.noPan) { 

     _panStart.copy(getMouseOnScreen(event.pageX, event.pageY)); 
     _panEnd.copy(_panStart); 

    } 

    //added by default 
    //document.addEventListener('mousemove', mousemove, false); 
    //document.addEventListener('mouseup', mouseup, false); 

    _this.dispatchEvent(startEvent); 

    } 

    function mousemove(event) { 



    if (_this.enabled === false) return; 

    event.preventDefault(); 
    event.stopPropagation(); 

    if (_state === STATE.ROTATE && ! _this.noRotate) { 

     _movePrev.copy(_moveCurr); 
     _moveCurr.copy(getMouseOnCircle(event.pageX, event.pageY)); 

    } else if (_state === STATE.ZOOM && ! _this.noZoom) { 

     _zoomEnd.copy(getMouseOnScreen(event.pageX, event.pageY)); 

    } else if (_state === STATE.PAN && ! _this.noPan) { 

     _panEnd.copy(getMouseOnScreen(event.pageX, event.pageY)); 

    } 

    } 

    function mouseup(event) { 

    if (_this.enabled === false) return; 

    event.preventDefault(); 
    event.stopPropagation(); 

    //_state = STATE.NONE; 

    //document.removeEventListener('mousemove', mousemove); 
    //document.removeEventListener('mouseup', mouseup); 
    _this.dispatchEvent(endEvent); 

    } 

    function mousewheel(event) { 

    if (_this.enabled === false) return; 

    event.preventDefault(); 
    event.stopPropagation(); 

    switch (event.deltaMode) { 

     case 2: 
     // Zoom in pages 
     _zoomStart.y -= event.deltaY * 0.025; 
     break; 

     case 1: 
     // Zoom in lines 
     _zoomStart.y -= event.deltaY * 0.01; 
     break; 

     default: 
     // undefined, 0, assume pixels 
     _zoomStart.y -= event.deltaY * 0.00025; 
     break; 

    } 

    _this.dispatchEvent(startEvent); 
    _this.dispatchEvent(endEvent); 

    } 

    function touchstart(event) { 

    if (_this.enabled === false) return; 

    switch (event.touches.length) { 

     case 1: 
     _state = STATE.TOUCH_ROTATE; 
     _moveCurr.copy(getMouseOnCircle(event.touches[ 0 ].pageX, event.touches[ 0 ].pageY)); 
     _movePrev.copy(_moveCurr); 
     break; 

     default: // 2 or more 
     _state = STATE.TOUCH_ZOOM_PAN; 
     var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX; 
     var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY; 
     _touchZoomDistanceEnd = _touchZoomDistanceStart = Math.sqrt(dx * dx + dy * dy); 

     var x = (event.touches[ 0 ].pageX + event.touches[ 1 ].pageX)/2; 
     var y = (event.touches[ 0 ].pageY + event.touches[ 1 ].pageY)/2; 
     _panStart.copy(getMouseOnScreen(x, y)); 
     _panEnd.copy(_panStart); 
     break; 

    } 

    _this.dispatchEvent(startEvent); 

    } 

    function touchmove(event) { 

    if (_this.enabled === false) return; 

    event.preventDefault(); 
    event.stopPropagation(); 

    switch (event.touches.length) { 

     case 1: 
     _movePrev.copy(_moveCurr); 
     _moveCurr.copy(getMouseOnCircle(event.touches[ 0 ].pageX, event.touches[ 0 ].pageY)); 
     break; 

     default: // 2 or more 
     var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX; 
     var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY; 
     _touchZoomDistanceEnd = Math.sqrt(dx * dx + dy * dy); 

     var x = (event.touches[ 0 ].pageX + event.touches[ 1 ].pageX)/2; 
     var y = (event.touches[ 0 ].pageY + event.touches[ 1 ].pageY)/2; 
     _panEnd.copy(getMouseOnScreen(x, y)); 
     break; 

    } 

    } 

    function touchend(event) { 

    if (_this.enabled === false) return; 

    switch (event.touches.length) { 

     case 0: 
     _state = STATE.NONE; 
     break; 

     case 1: 
     _state = STATE.TOUCH_ROTATE; 
     _moveCurr.copy(getMouseOnCircle(event.touches[ 0 ].pageX, event.touches[ 0 ].pageY)); 
     _movePrev.copy(_moveCurr); 
     break; 

    } 

    _this.dispatchEvent(endEvent); 

    } 

    function contextmenu(event) { 

    if (_this.enabled === false) return; 

    event.preventDefault(); 

    } 

    this.dispose = function() { 

    this.domElement.removeEventListener('contextmenu', contextmenu, false); 
    this.domElement.removeEventListener('mousedown', mousedown, false); 
    this.domElement.removeEventListener('wheel', mousewheel, false); 

    this.domElement.removeEventListener('touchstart', touchstart, false); 
    this.domElement.removeEventListener('touchend', touchend, false); 
    this.domElement.removeEventListener('touchmove', touchmove, false); 

    document.removeEventListener('mousemove', mousemove, false); 
    document.removeEventListener('mouseup', mouseup, false); 

    window.removeEventListener('keydown', keydown, false); 
    window.removeEventListener('keyup', keyup, false); 

    }; 

    this.domElement.addEventListener('contextmenu', contextmenu, false); 
    this.domElement.addEventListener('mousedown', mousedown, false); 
    this.domElement.addEventListener('wheel', mousewheel, false); 

    this.domElement.addEventListener('touchstart', touchstart, false); 
    this.domElement.addEventListener('touchend', touchend, false); 
    this.domElement.addEventListener('touchmove', touchmove, false); 

    window.addEventListener('keydown', keydown, false); 
    window.addEventListener('keyup', keyup, false); 

    this.handleResize(); 

    // force an update at start 
    this.update(); 

    document.addEventListener('mousemove', mousemove, false); 
    document.addEventListener('mouseup', mouseup, false); 
}; 

THREE.MyTrackballControls.prototype = Object.create(THREE.EventDispatcher.prototype); 
THREE.MyTrackballControls.prototype.constructor = THREE.MyTrackballControls; 


if (! Detector.webgl) Detector.addGetWebGLMessage(); 

var container, stats; 

var camera, controls, scene, renderer; 

var cross; 

init(); 
animate(); 

function init() { 

    camera = new THREE.PerspectiveCamera(60, window.innerWidth/window.innerHeight, 1, 1000); 
    camera.position.z = 500; 

    controls = new THREE.MyTrackballControls(camera); 

    controls.rotateSpeed = 2.0; 
    controls.zoomSpeed = 1.2; 
    controls.panSpeed = 0.8; 


    controls.noPan = false; 

    controls.staticMoving = false; 
    controls.dynamicDampingFactor = 0.3; 

    controls.keys = [ 65, 83, 68 ]; 

    controls.addEventListener( 'change', render); 

    // world 

    scene = new THREE.Scene(); 
    scene.fog = new THREE.FogExp2(0xcccccc, 0.002); 

    var geometry = new THREE.CylinderGeometry(0, 10, 100, 16, 1); 
    var material = new THREE.MeshPhongMaterial({ color: 0xdddddd, specular: 0x009900, shininess: 30, shading: THREE.SmoothShading }); 



    for (var i = 0; i < 200; i ++) { 

    var mesh = new THREE.Mesh(geometry, material); 
    mesh.position.x = (Math.random() - 0.5) * 500; 
    mesh.position.y = (Math.random() - 0.5) * 500; 
    mesh.position.z = (Math.random() - 0.5) * 500; 
    mesh.updateMatrix(); 
    mesh.matrixAutoUpdate = false; 
    scene.add(mesh); 

    } 


    // lights 

    light = new THREE.DirectionalLight(0xffffff); 
    light.position.set(1, 1, 1); 
    scene.add(light); 

    light = new THREE.DirectionalLight(0x002288); 
    light.position.set(-1, -1, -1); 
    scene.add(light); 

    light = new THREE.AmbientLight(0x222222); 
    scene.add(light); 


    renderer = new THREE.WebGLRenderer({ antialias: false }); 
    renderer.setClearColor(scene.fog.color); 
    renderer.setPixelRatio(window.devicePixelRatio); 
    renderer.setSize(window.innerWidth, window.innerHeight); 

    container = document.getElementById('container'); 
    container.appendChild(renderer.domElement); 

    stats = new Stats(); 
    stats.domElement.style.position = 'absolute'; 
    stats.domElement.style.top = '0px'; 
    stats.domElement.style.zIndex = 100; 
    container.appendChild(stats.domElement); 

    // 

    window.addEventListener('resize', onWindowResize, false); 
    // 

    render(); 

} 

function onWindowResize() { 

    camera.aspect = window.innerWidth/window.innerHeight; 
    camera.updateProjectionMatrix(); 

    renderer.setSize(window.innerWidth, window.innerHeight); 

    controls.handleResize(); 

    render(); 

} 

function animate() { 

    requestAnimationFrame(animate); 
    controls.update(); 


} 

function render() { 

    renderer.render(scene, camera); 
    stats.update(); 
} 
+0

J'ai essayé ce code et je continue à recevoir des messages d'erreur qui disent « ne peut pas lire la propriété « mise à jour » à: THREE.MyTrackballControls.render THREE.MyTrackballControls.dispatchEvent THREE.MyTrackballControls.update » –

+0

Un exemple vivant de travail est fourni dans le lien codepen que j'ai créé ... plus que cela serait difficile à faire: https://codepen.io/leefsmp/pen/zEvaBK –