右键单击 svg 元素的自定义上下文菜单位置

Custom Context Menu Position on right clicking svg element

我正在尝试将 Bootstrap 4 下拉菜单实现为上下文菜单。 一切正常,但面临下拉列表的 lefttop css 属性 问题。

DOM结构?

<div class="col">
    <div class="dropdown-menu dropdown-menu-right shadow-sm" style="width: 15rem;" id="contextMenu">
        <a class="dropdown-item" href="#">Action</a>
        <a class="dropdown-item" href="#">Another action</a>
        <a class="dropdown-item" href="#">Something else here</a>
        <div class="dropdown-divider"></div>
        <a class="dropdown-item" href="#">Separated link</a>
    </div>
    <div class="h-75">
        <svg id="preview" class="shadow" height="100%" viewBox="0 0 1920 1080"
             preserveAspectRatio="xMinYMin meet" xmlns="http://www.w3.org/2000/svg">
            <g class="sjx-svg-wrapper">
                <image id="blabla" class="drag-svg"
                       href="https://mdn.mozillademos.org/files/6457/mdn_logo_only_color.png" height="200"
                       width="200"/>
            </g>
        </svg>
    </div>
</div>

我尝试了什么?

    $(document).on("contextmenu", 'g.sjx-svg-wrapper', function (e) {
        // TRIES HERE
        let left = e.offsetX;
        let top = e.offsetY;

        $("#contextMenu").css({
            display: "block",
            left: left,
            top: top
        }).addClass("show");

        return false;
    });

问题是什么?

问题是下拉菜单并不像我们右键单击时出现的普通上下文菜单那样准确地显示在指针处。

而且当 svg 容器的宽度改变时,下拉位置会错位(即使再次右键单击)。

我尝试过使用偏移量的其他解决方案,但没有达到目的。 所以请提供一个可靠的方法来解决这个问题。

也许只是使用 event.pageXevent.pageY 而不是 event.offsetXevent.offsetY...

.offsetX:

The offsetX read-only property of the MouseEvent interface provides the offset in the X coordinate of the mouse pointer between that event and the padding edge of the target node.

.pageX:

The pageX read-only property of the MouseEvent interface returns the X (horizontal) coordinate (in pixels) at which the mouse was clicked, relative to the left edge of the entire document.

$(document).on("contextmenu", 'g.sjx-svg-wrapper', function(e) {
  // TRIES HERE
  let left = e.pageX;
  let top = e.pageY;

  $("#contextMenu").css({
    display: "block",
    left: left,
    top: top
  }).addClass("show");

  return false;
});
#contextMenu{
  display:none;
  position: absolute;
  padding: 20px;
  background-color: white;
  border: 1px solid red;
  box-shadow: 2px 2px grey;
  
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="col">
  <div class="dropdown-menu dropdown-menu-right shadow-sm" style="width: 15rem;" id="contextMenu">
    <a class="dropdown-item" href="#">Action</a>
    <a class="dropdown-item" href="#">Another action</a>
    <a class="dropdown-item" href="#">Something else here</a>
    <div class="dropdown-divider"></div>
    <a class="dropdown-item" href="#">Separated link</a>
  </div>
  <div class="h-75">
    <svg id="preview" class="shadow" height="100%" viewBox="0 0 1920 1080" preserveAspectRatio="xMinYMin meet" xmlns="http://www.w3.org/2000/svg">
            <g class="sjx-svg-wrapper">
                <image id="blabla" class="drag-svg"
                       href="https://mdn.mozillademos.org/files/6457/mdn_logo_only_color.png" height="200"
                       width="200"/>
            </g>
        </svg>
  </div>
</div>

<div id="contextMenu">CONTEXT</div>

我想我刚刚弄明白了:

我刚才做的是从 e.clientXe.clientY 坐标(这基本上是鼠标在页面上的位置)中减去容器(宽度变化)的位置坐标(x,y) .

所以这里是答案:

var prevElm = $('.h-75').offset();

let left = (e.clientX - prevElm.left) + 15;
let top = (e.clientY - prevElm.top) + 45;

我认为这仅适用于我的案例页面,其他人可能只需要 e.clientXe.clientY