Changer la position des popovers Bootstrap en fonction de la position X du popover par rapport au bord de la fenêtre?

83

J'ai parcouru Internet de très loin et même si j'ai trouvé ce post de stackoverflow perspicace. Est-il possible de changer la position des popovers Bootstrap en fonction de la largeur de l'écran? , il n'a toujours pas répondu à ma question, probablement en raison de ma difficulté à comprendre la position / décalage.

Voici ce que j'essaye de faire. Je veux que la position Twitter Bootstap Popover soit à DROITE à moins que la popover hotspot ne soit positionnée au-delà de la fenêtre, alors je veux qu'elle soit positionnée à GAUCHE. Je crée une application Web iPad qui a des points chauds, lorsque vous appuyez sur un point d'accès, des informations s'affichent mais je ne veux pas qu'elles apparaissent en dehors de la fenêtre lorsque le défilement horizontal est verrouillé.

Je pense que ce serait quelque chose comme ça:

$('.infopoint').popover({
        trigger:'hover',
        animation: false,
        placement: wheretoplace 
    });
    function wheretoplace(){
        var myLeft = $(this).offset.left;

        if (myLeft<500) return 'left';
        return 'right';
    }

Pensées? Merci!

j0e
la source

Réponses:

177

Je viens de remarquer que l' option de placement peut être une chaîne ou une fonction renvoyant une chaîne qui effectue le calcul à chaque fois que vous cliquez sur un lien popover.

Cela facilite grandement la réplication de ce que vous avez fait sans la fonction initiale $ .each :

var options = {
    placement: function (context, source) {
        var position = $(source).position();

        if (position.left > 515) {
            return "left";
        }

        if (position.left < 515) {
            return "right";
        }

        if (position.top < 110){
            return "bottom";
        }

        return "top";
    }
    , trigger: "click"
};
$(".infopoint").popover(options);
bchhun
la source
1
C'est le meilleur moyen car autone fonctionne pas toujours parfaitement en fonction de la mise en page et du contenu que vous mettez dans le popover.
Bron Davies
Merci pour cela. Est-ce normal que nous l'utilisions sans vous être attribué?
D.Tate
6
@ D.Tate Je crois que tout sur stackoverflow devrait être utilisable sans aucune attribution.
Devenez
3
Quelle est la logique du choix left 515&top 110
Murali Murugesan
1
@MuraliMurugesan aucune logique du tout; J'ai simplement utilisé les chiffres fournis dans la question. Vous pouvez utiliser ce que vous voulez.
bchhun
35

Pour Bootstrap 3, il y a

placement: 'auto right'

ce qui est plus facile. Par défaut, ce sera à droite, mais si l'élément est situé dans la partie droite de l'écran, le popover sera à gauche. Donc ça devrait être:

$('.infopoint').popover({
   trigger:'hover',
   animation: false,
   placement: 'auto right'
});
Hans Tiono
la source
2
J'ai eu des expériences mitigées avec cela jusqu'à présent. Je n'ai pas encore regardé la source Bootstrap, mais il semble qu'elle ne prend en compte que le positionnement de l'élément, et non la position à venir du popover. Ainsi, les éléments qui sont sur le bord ou au-delà du bord de la fenêtre obtiennent un popover au plus au bord, mais les éléments qui sont juste au-dessus du bord (par exemple) obtiennent un popover sous le pli.
Daved
1
Non, cela ne devrait pas être la réponse acceptée. L'option "placement" ne prend pas en compte les bords de la fenêtre , uniquement les limites élément parent / conteneur. Donc, si vous avez par exemple 'auto top', il apparaîtra toujours dans la fenêtre supérieure lorsque vous faites défiler vers le bas.
rzb
31

Sur la base de la documentation, vous devriez pouvoir utiliser autoen combinaison avec l'emplacement préféré, par exempleauto left

http://getbootstrap.com/javascript/#popovers : "Lorsque" auto "est spécifié, il réorientera dynamiquement le popover. Par exemple, si le placement est" auto left ", l'info-bulle s'affichera à gauche si possible, sinon il s'affichera à droite. "

J'essayais de faire la même chose puis je me suis rendu compte que cette fonctionnalité existait déjà.

Hamish Rouse
la source
2
la gauche automatique donne une barre de défilement horizontale
Jitendra Vyas
3
Vous pouvez également spécifier a viewportsi vous ne souhaitez pas qu'il soit calculé en fonction du parent des éléments.
allicarn
5

J'ai donc trouvé un moyen de le faire efficacement. Pour mon projet particulier, je construis un site Web iPad, donc je savais exactement quelle serait la valeur du pixel X / Y pour atteindre le bord de l'écran. Vos valeurs thisX et thisY varieront.

Étant donné que les popovers sont de toute façon placés par style en ligne, je saisis simplement les valeurs gauche et supérieure de chaque lien pour décider dans quelle direction le popover doit être. Ceci est fait en ajoutant des valeurs de données html5 que .popover () utilise lors de l'exécution.

if ($('.infopoint').length>0){
    $('.infopoint').each(function(){
        var thisX = $(this).css('left').replace('px','');
        var thisY = $(this).css('top').replace('px','');
        if (thisX > 515)
            $(this).attr('data-placement','left');
        if (thisX < 515)
            $(this).attr('data-placement','right');
        if (thisY > 480)
            $(this).attr('data-placement','top');
        if (thisY < 110)
            $(this).attr('data-placement','bottom');
    });
    $('.infopoint').popover({
        trigger:'hover',
        animation: false,
        html: true
    });
}

Tous les commentaires / améliorations sont les bienvenus, mais cela fait le travail si vous êtes prêt à entrer les valeurs manuellement.

j0e
la source
2

La réponse de bchhun m'a mis sur la bonne voie, mais je voulais vérifier l'espace réel disponible entre la source et le bord de la fenêtre. Je voulais également respecter l'attribut de placement de données en tant que préférence avec des solutions de secours appropriées s'il n'y avait pas assez d'espace. De cette façon, "droite" irait toujours à droite à moins qu'il n'y ait pas assez d'espace pour que le popover s'affiche sur le côté droit, par exemple. C'est ainsi que je l'ai géré. Cela fonctionne pour moi, mais cela me semble un peu encombrant. Si quelqu'un a des idées pour une solution plus propre et plus concise, je serais intéressé de la voir.

var options = {
  placement: function (context, source) {
    var $win, $source, winWidth, popoverWidth, popoverHeight, offset, toRight, toLeft, placement, scrollTop;

    $win = $(window);
    $source = $(source);
    placement = $source.attr('data-placement');
    popoverWidth = 400;
    popoverHeight = 110;
    offset = $source.offset();

    // Check for horizontal positioning and try to use it.
    if (placement.match(/^right|left$/)) {
      winWidth = $win.width();
      toRight = winWidth - offset.left - source.offsetWidth;
      toLeft = offset.left;

      if (placement === 'left') {
        if (toLeft > popoverWidth) {
          return 'left';
        }
        else if (toRight > popoverWidth) {
          return 'right';
        }
      }
      else {
        if (toRight > popoverWidth) {
          return 'right';
        }
        else if (toLeft > popoverWidth) {
          return 'left';
        }
      }
    }

    // Handle vertical positioning.
    scrollTop = $win.scrollTop();
    if (placement === 'bottom') {
      if (($win.height() + scrollTop) - (offset.top + source.offsetHeight) > popoverHeight) {
        return 'bottom';
      }
      return 'top';
    }
    else {
      if (offset.top - scrollTop > popoverHeight) {
        return 'top';
      }
      return 'bottom';
    }
  },
  trigger: 'click'
};
$('.infopoint').popover(options);
chassant maxwell
la source
1

Vous pouvez également essayer celui-ci,

==> Obtenir la position cible / source dans la fenêtre
==> Vérifiez si l'espace à partir du bas est inférieur à la hauteur de votre info-bulle
==> Si l'espace à partir du bas est inférieur à la hauteur de votre info-bulle, faites simplement défiler la page vers le haut

placement: function(context, source){
  //get target/source position in viewport
  var bounds = $(source)[0].getBoundingClientRect();
      winHeight = $(window).height();

  //check wheather space from bottom is less that your tooltip height
  var rBottom = winHeight - bounds.bottom;

  //Consider 180 == your Tooltip height
  //if space from bottom is less that your tooltip height, this will scrolls page up
  //We are keeping tooltip position is fixed(at bottom)

  if (rBottom < 180){
    $('html, body').animate({ scrollTop: $(document).scrollTop()+180 }, 'slow');
  }

  return "bottom";
}
Mohan Dere
la source
0

Vous pouvez utiliser le placement automatique des données comme data-placement = "auto left". Il s'ajustera automatiquement en fonction de la taille de votre écran et le placement par défaut sera laissé.

Abhishek Anand
la source
0

En plus de la bonne réponse de bchhun, si vous voulez un positionnement absoulte, vous pouvez le faire

var options = {
    placement: function (context, source) {
         setTimeout(function () {
               $(context).css('top',(source.getBoundingClientRect().top+ 500) + 'px')
         },0)
         return "top";
    },
    trigger: "click"
};
$(".infopoint").popover(options);
pomme16
la source
0

J'ai résolu mon problème dans AngularJS comme suit:

var configPopOver = {
        animation: 500,
        container: 'body',
        placement: function (context, source) {
                    var elBounding = source.getBoundingClientRect();
                    var pageWidth = angular.element('body')[0].clientWidth
                    var pageHeith = angular.element('body')[0].clientHeith

                    if (elBounding.left > (pageWidth*0.34) && elBounding.width < (pageWidth*0.67)) {
                        return "left";
                    }

                    if (elBounding.left < (pageWidth*0.34) && elBounding.width < (pageWidth*0.67)) {
                        return "right";
                    }

                    if (elBounding.top < 110){
                        return "bottom";
                    }

                    return "top";
                },
        html: true
    };

Cette fonction fait la position du flotteur de popover Bootstrap à la meilleure position, en fonction de la position de l'élément.

Gustavo Benício
la source
0
$scope.popoverPostion = function(event){
    $scope.pos = '';

       if(event.x <= 207 && event.x >= 140){
           $scope.pos = 'top';
           event.x = '';
       }
       else if(event.x < 140){
           $scope.pos = 'top-left';
           event.x = '';
       }
       else if(event.x > 207){
           $scope.pos = 'top-right';
           event.x = '';
       }

};
Suvra
la source
-2

Vous pouvez également essayer celui-ci si vous en avez besoin à presque tous les endroits de la page.

Vous pouvez le configurer de manière générale, puis l'utiliser.

De cette façon, vous pouvez également utiliser un élément HTML et tout ce que vous voulez :)

$(document).ready(function()
                  {
  var options =
      {
        placement: function (context, source)
        {
          var position = $(source).position();
          var content_width = 515;  //Can be found from a JS function for more dynamic output
          var content_height = 110;  //Can be found from a JS function for more dynamic output

          if (position.left > content_width)
          {
            return "left";
          }

          if (position.left < content_width)
          {
            return "right";
          }

          if (position.top < content_height)
          {
            return "bottom";
          }

          return "top";
        }
        , trigger: "hover"
        , animation: "true"
        , html:"true"
      };
  $('[data-toggle="popover"]').popover(options);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js"></script>
<link href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet"/>
<script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>


<div class="container">
	<h3>Popover Example</h3>
	<a id="try_ppover" href="#" data-toggle="popover" title="Popover HTML Header" data-content="<div class='jumbotron'>Some HTML content inside the popover</div>">Toggle popover</a>
</div>

Une addition


Pour définir plus d'options, vous pouvez aller ici .

Encore plus peut être trouvé ici .

Mise à jour


Si vous voulez que le popup après le clic, vous pouvez changer l'option JS pour trigger: "click"aimer ceci-

        return ..;
    }
    ......
    , trigger: "click"
    ......
};

Vous pouvez également le personnaliser dans une publicité HTML data-trigger="click"comme celle- ci-

<a id="try_ppover" href="#" data-toggle="popover" data-trigger="click" title="Popover Header" data-content="<div class='jumbotron'>Some content inside the popover</div>">Toggle popover</a>

Je pense que ce sera du code plus orienté et plus réutilisable et plus utile à tous :).

Abrar Jahin
la source