Bootstrap Popover วางตำแหน่งอัตโนมัติไม่ถูกต้อง

ความเป็นมา: ฉันใช้ OpenLayers V3 เพื่อแสดงแผนที่ที่มี "เครื่องหมาย/ไอคอน" หลายอันเพื่อทำเครื่องหมายตำแหน่งของที่อยู่ที่ฉันต้องการแสดงบนแผนที่ ฉันใช้จาวาสคริปต์เพื่อแสดงป๊อปโอเวอร์ทุกครั้งที่ผู้ใช้วางเมาส์เหนือเครื่องหมายอันใดอันหนึ่ง (ป๊อปโอเวอร์ "marker" fyi จะแสดงที่อยู่สำหรับตำแหน่งเครื่องหมาย) คุณจะเห็นว่าฉันตั้งค่าตำแหน่งบูตสแตรปโอเวอร์เป็น "อัตโนมัติด้านบน" เพื่อให้แน่ใจว่าป๊อปโอเวอร์ใดๆ ที่อยู่ใกล้กับขอบของแผนที่จะแสดงขึ้น เพื่อไม่ให้พวกมันวิ่งออกนอกขอบของแผนที่ (เช่น รับ ทางลัด)

ปัญหา: เมื่อเครื่องหมายตัวใดตัวหนึ่งอยู่ใกล้ขอบด้านบนของแผนที่ การตั้งค่าตำแหน่ง "ด้านบนอัตโนมัติ" จะปรับตำแหน่งสำหรับป๊อปโอเวอร์ "ของเครื่องหมาย" นั้นอย่างถูกต้อง เพื่อให้ยังคงมองเห็นได้ (นั่นคือ ป๊อปโอเวอร์จะแสดงที่ ด้านล่างของเครื่องหมาย) แต่น่าเสียดายที่ "เครื่องหมาย" อื่นๆ ทั้งหมดบนแผนที่ดูเหมือนจะ "สืบทอด" "ตำแหน่งด้านล่าง" นี้โดยไม่จำเป็น ด้วยเหตุนี้ จึงทำให้ "เครื่องหมาย" ใกล้ด้านล่างสุดของหน้ามีจุดตัดป๊อปโอเวอร์

ตัวอย่างโค้ดจาวาสคริปต์:

หมายเหตุ: มีโค้ดจำนวนมากที่นี่ แต่ฉันคิดว่ามันจะดีกว่าถ้ารวมโค้ดทั้งหมดไว้แทนที่จะละเว้นบางอย่างที่อาจเกี่ยวข้องกับการแก้ปัญหา นอกจากนี้ ฉันควรทราบด้วยว่าจาวาสคริปต์นั้น "ป้อน" วัตถุที่มีลักษณะดังนี้:

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

ลูปที่ซ้อนกันในโค้ดจาวาสคริปต์ Drawmap ใช้เพื่อวนซ้ำผ่านออบเจ็กต์นี้และตั้งค่า/บันทึกค่าในซอฟต์แวร์ 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 ที่เกี่ยวข้อง:

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

CSS ที่เกี่ยวข้อง:

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

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

กำลังพยายามระบุว่าเหตุใดฉันจึงเห็นพฤติกรรมที่ระบุไว้ข้างต้นในสรุปปัญหา

ไชโย


person user2101068    schedule 14.03.2015    source แหล่งที่มา


คำตอบ (1)


'auto top' ไม่ใช่ตัวเลือกตำแหน่งที่ถูกต้องสำหรับ ol.Overlay ตัวเลือกที่ถูกต้องคือ 'bottom-left', 'bottom-center', 'bottom-right', 'center-left', 'center-center', 'center-right', 'top-left', 'top-center', 'top-right' เพื่อให้แน่ใจว่าป๊อปโอเวอร์ของคุณมองเห็นได้ คุณอาจต้องกำหนดค่า ol.Overlay ของคุณด้วยตัวเลือก autoPan ที่ตั้งค่าเป็นจริง ดังนั้นการกำหนดค่าโอเวอร์เลย์ที่ถูกต้องจะมีลักษณะดังนี้:

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

รหัส Popover ของคุณอาจจะทำให้ง่ายขึ้นเล็กน้อย บางทีคุณอาจต้องการดูตัวอย่างอย่างเป็นทางการของ OpenLayers 3 + Bootstrap Popover เพื่อเป็นแรงบันดาลใจ: http://openlayers.org/en/v3.3.0/examples/overlay.html

person ahocevar    schedule 22.03.2015
comment
@tsauerwein คุณแน่ใจเหรอ? ฉันคิดว่าเมื่อไม่ได้ตั้งค่าการวางตำแหน่งป๊อปโอเวอร์เป็นแบบอัตโนมัติ มันก็ควรจะใช้งานได้ - person ahocevar; 24.03.2015