¿Cambiar la posición de los elementos emergentes de Bootstrap en función de la posición X del elemento emergente en relación con el borde de la ventana?

83

He rastreado Internet a lo largo y ancho y, aunque encontré esta publicación de stackoverflow reveladora ¿Es posible cambiar la posición de los popovers de Bootstrap en función del ancho de la pantalla? , todavía no respondió a mi pregunta, probablemente debido a mi dificultad para entender la posición / compensación.

Esto es lo que estoy tratando de hacer. Quiero que la posición de Twitter Bootstap Popover sea CORRECTA a menos que la ventana emergente del hotspot se coloque más allá de la ventana gráfica, luego quiero que se coloque a la IZQUIERDA. Estoy creando una aplicación web para iPad que tiene puntos de acceso, cuando presionas un punto de acceso, aparece información, pero no quiero que aparezca fuera de la ventana gráfica cuando el desplazamiento horizontal está bloqueado.

Estoy pensando que sería algo como esto:

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

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

Pensamientos ¡Gracias!

j0e
fuente

Respuestas:

177

Me acabo de dar cuenta de que la opción de ubicación podría ser una cadena o una función que devuelve una cadena que realiza el cálculo cada vez que hace clic en un enlace popover.

Esto hace que sea muy fácil replicar lo que hizo sin la función $ .each inicial :

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
fuente
1
Esta es la mejor manera porque autono siempre funciona perfectamente dependiendo del diseño de la página y el contenido que pones en el popover.
Bron Davies
Gracias por esto. ¿Está bien si lo usamos sin atribución a usted?
D.Tate
6
@ D.Tate Creo que todo en stackoverflow debería ser utilizable sin ninguna atribución. Vuélvete loco con eso;)
bchhun
3
¿Cuál es la lógica de elegir left 515y?top 110
Murali Murugesan
1
@MuraliMurugesan no tiene ninguna lógica; Simplemente utilicé los números proporcionados en la pregunta. Puedes usar lo que quieras.
bchhun
35

Para Bootstrap 3, hay

placement: 'auto right'

que es más fácil. Por defecto, estará a la derecha, pero si el elemento está ubicado en el lado derecho de la pantalla, el popover estará a la izquierda. Entonces debería ser:

$('.infopoint').popover({
   trigger:'hover',
   animation: false,
   placement: 'auto right'
});
Hans Tiono
fuente
2
Hasta ahora he tenido experiencias encontradas con esto. Todavía no he mirado la fuente de Bootstrap, pero parece que solo tiene en cuenta el posicionamiento del elemento, y no la posición futura del popover. Entonces, los elementos que están en el borde o más allá del borde de la ventana obtienen un popover en el borde como máximo, pero los elementos que están justo encima del borde (por ejemplo) obtienen un popover debajo del pliegue.
Daved el
1
No, no debería ser la respuesta aceptada. La opción de "ubicación" no tiene en cuenta los bordes de la ventana , solo los límites del elemento principal / contenedor. Por lo tanto, si tiene, por ejemplo, 'auto top', todavía se mostrará en la ventana superior cuando se desplace hacia abajo.
rzb
31

Según la documentación, debería poder utilizar autoen combinación con la ubicación preferida, p. Ej.auto left

http://getbootstrap.com/javascript/#popovers : "Cuando se especifica" auto ", se reorientará dinámicamente la ventana emergente. Por ejemplo, si la ubicación es" auto left ", la información sobre herramientas se mostrará a la izquierda cuando sea posible; de ​​lo contrario se mostrará a la derecha ".

Estaba tratando de hacer lo mismo y luego me di cuenta de que esta funcionalidad ya existía.

Hamish Rouse
fuente
2
la izquierda automática da barra de desplazamiento horizontal
Jitendra Vyas
3
También puede especificar un viewportsi no desea que se calcule en función del padre de los elementos.
allicarn
5

Entonces descubrí una manera de hacer esto de manera efectiva. Para mi proyecto en particular, estoy construyendo un sitio web para iPad, así que sabía exactamente cuál sería el valor de píxel X / Y para llegar al borde de la pantalla. Sus valores thisX y thisY variarán.

Dado que los popovers se colocan mediante el estilo en línea de todos modos, simplemente tomo los valores izquierdo y superior de cada enlace para decidir en qué dirección debería estar el popover. Esto se hace agregando valores de datos html5 que .popover () usa en la ejecución.

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
    });
}

Cualquier comentario / mejora es bienvenido, pero esto hace el trabajo si está dispuesto a ingresar los valores manualmente.

j0e
fuente
2

La respuesta de bchhun me puso en el camino correcto, pero quería verificar el espacio real disponible entre la fuente y el borde de la ventana gráfica. También quería respetar el atributo de ubicación de datos como una preferencia con las alternativas apropiadas si no hubiera suficiente espacio. De esa manera, "correcto" siempre irá a la derecha a menos que no haya suficiente espacio para que la ventana emergente aparezca en el lado derecho, por ejemplo. Esta fue la forma en que lo manejé. Funciona para mí, pero se siente un poco incómodo. Si alguien tiene alguna idea para una solución más limpia y concisa, me interesaría verla.

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);
persiguiendo a Maxwell
fuente
1

También puedes probar este,

==> Obtener la posición de destino / origen en la ventana gráfica
==> Verifique si el espacio desde la parte inferior es menor que la altura de la información sobre herramientas
==> Si el espacio desde la parte inferior es menor que la altura de la información sobre herramientas, simplemente desplácese hacia arriba

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
fuente
0

Puede utilizar auto en la ubicación de datos como data-location = "auto left". Se ajustará automáticamente según el tamaño de la pantalla y se dejará la ubicación predeterminada.

Abhishek Anand
fuente
0

Además de la gran respuesta de bchhun, si quieres un posicionamiento absoluto, puedes hacer esto

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

Resolví mi problema en AngularJS de la siguiente manera:

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
    };

Esta función hace que la posición de Bootstrap popover flote a la mejor posición, según la posición del elemento.

Gustavo Benício
fuente
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
fuente
-2

También puede probar este si lo necesita en casi todos los lugares de la página.

Puedes configurarlo de forma general y luego usarlo.

De esta manera, también puede usar el elemento HTML y cualquier cosa que desee :)

$(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>

Adición


Para configurar más opciones, puede ir aquí .

Incluso se pueden encontrar más aquí .

Actualizar


Si desea que aparezca la ventana emergente después de hacer clic, puede cambiar la opción JS para trigger: "click"así-

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

U también puede personalizarlo en HTML ading data-trigger="click"como este-

<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>

Creo que será un código más orientado y más reutilizable y más útil para todos :).

Abrar Jahin
fuente