Penempatan otomatis Bootstrap Popover salah diterapkan

Latar belakang: Saya menggunakan OpenLayers V3 untuk menampilkan peta dengan beberapa "penanda/ikon" untuk menandai lokasi alamat yang ingin saya tampilkan di peta. Saya menggunakan javascript untuk menampilkan popover kapan saja pengguna mengarahkan kursor ke salah satu penanda (fyi "marker" popover menampilkan alamat jalan untuk lokasi penanda). Anda akan melihat bahwa saya menyetel nilai penempatan bootstrap popover ke "auto top" untuk memastikan bahwa popover apa pun di dekat tepi peta akan ditampilkan sehingga tidak keluar dari tepi peta (yaitu, dapatkan memotong).

Masalah: Bila salah satu penanda berada di dekat tepi atas peta, setelan penempatan "atas otomatis" akan menyesuaikan dengan tepat penempatan untuk popover "penanda" tersebut sehingga tetap terlihat (yaitu, popover ditampilkan di bagian bawah penanda) namun sayangnya semua "penanda" lain pada peta sepertinya tidak perlu "mewarisi" "penempatan bawah" ini. Akibatnya, hal ini menyebabkan "penanda" di dekat bagian bawah halaman terpotong popovernya.

Contoh kode javascript:

Catatan: Ada banyak kode di sini tapi saya pikir akan lebih baik untuk memasukkan semuanya daripada mengabaikan sesuatu yang mungkin relevan untuk menyelesaikan masalah. Juga, saya harus mencatat bahwa javascript "diberi makan" sebuah objek yang terlihat sebagai berikut:

{'pintype1.filename.png':
["Address", [Longitude,Latitude]],
["Address", [Longitude,Latitude]],
etc., etc.
'pintype2.filename.png':
["Address", [Longitude,Latitude]],
["Address", [Longitude,Latitude]]
etc., 
etc.,
}

Loop bersarang dalam kode javascript drawmap digunakan untuk melakukan loop melalui objek ini dan mengatur/menyimpan nilai dalam perangkat lunak OpenLayers.

window.RentMyThing = window.RentMyThing || {}
window.RentMyThing.drawMap = function drawMap (mapAttributesPlus) {
var popuplabel = '';
var iconLocations = [];
var vectorSource = new ol.source.Vector({
 //create empty vector -- not sure if this is needed??????
});
$('.map').html('');
// Outer Loop to retrieve each pin type
Object.keys(mapAttributesPlus).forEach(function(pinType) {


  // Inner Loop to retrieve all coordinates associated with each pin type
  mapAttributesPlus[pinType].forEach(function(coords) {

    var iconLocation = ol.proj.transform([coords[1][0], coords[1][1]], 'EPSG:4326', 'EPSG:3857')
    iconLocations.push(iconLocation)
    popupLabel = coords[0]
    console.log("Address: " + coords[0] + "Lon/Lat: " + coords[1][0] + ', ' + coords[1][1]);

    var iconFeature = new ol.Feature({
      geometry: new ol.geom.Point(iconLocation),
      // Added line for popup
      name: popupLabel
    })

    // Create Pin styling
    iconFeature.setStyle(
      new ol.style.Style({
        image: new ol.style.Icon({
          anchor: [0.2, 1],
          anchorXUnits: 'fraction',
          anchorYUnits: 'pixels',
          opacity: 0.75,
          src: pinType  // Set pin type
        })
      })
    )
    iconFeature.on('mouseover', function() {alert('hover')})
    vectorSource.addFeature(iconFeature);
  }) // End of inner loop - coords
}); // End of outer loop - pinType

// *************Create Vector Layer with Markers and Build Map ***************************
var vectorLayer = new ol.layer.Vector({
  source: vectorSource //      style: iconStyle
});

var map = new ol.Map({
  target: 'map',
  layers: [
    new ol.layer.Tile({
      title: "Rental Proximity Map",
      source: new ol.source.MapQuest({layer: 'osm'})
    }), vectorLayer],
  view: new ol.View({
   center: iconLocations[0],          // ??? Do i need a centering point at this point.
    zoom: 12
  }),
  controls: ol.control.defaults({
    attributionOptions: {
      collapsible: false
    }}).extend([
      new ol.control.ScaleLine()
    ])
});

// Bound the map if multiple points

var view = map.getView()
var extent = ol.extent.boundingExtent(iconLocations)
var size = map.getSize()
view.fitExtent(extent, size)
// If only one coordinate then binding map on that one point will produce
// a map that is zoomed in so close it will appear that no map is  displayed
// so we want to prevent the map zoom from going to high hence "if statement below"
if (view.getZoom() > 16) {
  view.setZoom(16);
}

Window.map = map;
// ***********************************************
//  Popup logic
// http://openlayers.org/en/v3.0.0/examples/icon.js
// ***********************************************

// The line below is required to get popup to appear
var element = $('.popup').first();

var popup = new ol.Overlay({
  element: element,
  positioning: 'auto top',
  stopEvent: false
});
map.addOverlay(popup);

var showing;
// display popup on click
map.on('pointermove', function(evt) {
  var feature = map.forEachFeatureAtPixel(evt.pixel,
      function(feature, layer) {
        return feature;
      });
  if (feature) {
    // Showing flag was added to remove popover from flickering when the mouse is hovered over the
    // icon/marker and there is incidental/minor movement in the mouse. Setting the show flag ensures
    // that you don't attempt to redraw the popup over and over (and get flickering) with minor mouse
    // movements
    if (! showing) {
      showing = true;
      var name = feature.get('name')
      var geometry = feature.getGeometry();
      var coord = geometry.getCoordinates();

      // Next line Added for testing
      // var element = $('.popup').this
      popup.setPosition(coord);

      // The line below fixed the scenario where clicking on one marker (e.g., 'renter')
      // and then immediately clicking on another marker (e.g, 'rental')  caused the wrong popup
      // content to appear on the newly clicked marker (e.g., popup displayed 'renter' rather than
      // rental). The line below uses jQuery method .attr to put the value of the newly clicked
      // marker value (i.e., name) into the HTML in the location that bootstrap pull the
      // the popup value (i.e., 'data-content')
      $(element).attr('data-content', name)

      $(element).popover({
        'trigger': 'hover click',
        'placement': 'auto top',
        'html': true,
        'content': name,
        // Had to add container to make "auto" placement work properly
      });
      $(element).popover('show');
    }
  } else {
    showing = false;
    $(element).popover('destroy');
  }
});

// change mouse cursor when over marker
map.on('pointermove', function(e) {
  if (e.dragging) {
    $(element).popover('destroy');
    return;
  }
  var pixel = map.getEventPixel(e.originalEvent);
  var hit = map.hasFeatureAtPixel(pixel);
  var target = document.getElementById(map.getTarget());
  target.style.cursor = hit ? 'pointer' : '';
});   } // End of drawmap function

HTML yang relevan:

<div id="map" class="map">
  <div class="popup" data-trigger="hover" data-toggle="popover" data-original-title="" title="" data-placement=""></div>
</div>

CSS yang relevan:

div#map {
  height: 400px;
  width: 512px;
}

.popover{
    width:160px;
    height:70px;
}

Mencoba mengidentifikasi alasan saya melihat perilaku yang disebutkan di atas dalam Ringkasan Masalah.

Bersulang.


person user2101068    schedule 14.03.2015    source sumber


Jawaban (1)


'auto top' bukan opsi penempatan yang valid untuk ol.Overlay. Opsi yang valid adalah 'bottom-left', 'bottom-center', 'bottom-right', 'center-left', 'center-center', 'center-right', 'top-left', 'top-center', 'top-right'. Untuk memastikan popover Anda terlihat, Anda mungkin ingin mengonfigurasi ol.Overlay Anda dengan opsi autoPan disetel ke true. Jadi konfigurasi overlay yang valid akan terlihat seperti ini:

var popup = new ol.Overlay({
  element: element,
  autoPan: true,
  positioning: 'center-center',
  stopEvent: false
});

Kode Popover Anda dapat disederhanakan sedikit. Mungkin Anda ingin melihat contoh resmi OpenLayers 3 + Bootstrap Popover untuk mendapatkan inspirasi: http://openlayers.org/en/v3.3.0/examples/overlay.html.

person ahocevar    schedule 22.03.2015
comment
@tsauerwein Apakah Anda yakin? Saya pikir ketika posisi popover tidak disetel ke otomatis, itu akan berfungsi. - person ahocevar; 24.03.2015