要获取d3中svg:image上放置的元素的xy坐标

问题描述 投票:1回答:1

这里我正在使用一个示例,在该示例中,我需要从svg:image元素中获取放置元素的X和Y值(使用Jquery拖放)。请检查我的codepen。在Codepen中,您可以看到一个rss图标,它是可拖动的元素,主要的大图像用作可放置的元素。使用d3 svg:image添加主要的大图像。在将rss图标拖放到主大图像时,应在放置点上附加一个rss图标。因此,在放置函数(JQuery)中,我添加了d3代码以将rss图标附加到主要的大图像上。

我已经使用4种方法来检索放置rss图标的点的X和Y值。在代码笔中,您可以看到:

提取xy正子的第一种方法:

 var currentPos = ui.helper.position();
 var parentOffset = $(this).parent().offset();
 var x1 = event.pageX - parentOffset.left;
 var y1 = event.pageY - parentOffset.top;

提取xy正子的第二种方法:

var dropPositionX = event.pageX - $(this).offset().left;
var dropPositionY = event.pageY - $(this).offset().top;
// Get mouse offset relative to dragged item:
var dragItemOffsetX = event.offsetX;
var dragItemOffsetY = event.offsetY;
// Get position of dragged item relative to drop target:
var x2 = dropPositionX-dragItemOffsetX;
var y2 = dropPositionY-dragItemOffsetY;

提取xy正子的第三种方法:

 var x3 = ui.offset.left - $(this).offset().left;
 var y3 = ui.offset.top - $(this).offset().top;

提取xy正子的第四种方法:

    var elem = document.getElementById("floor")
    var rect = elem.getBoundingClientRect();
            var scrollTop = document.documentElement.scrollTop?
                            document.documentElement.scrollTop:document.body.scrollTop;
            var scrollLeft = document.documentElement.scrollLeft?                   
                            document.documentElement.scrollLeft:document.body.scrollLeft;
            var elementLeft = rect.left+scrollLeft;  
            var elementTop = rect.top+scrollTop;

            var x4 = event.pageX-elementLeft;
            var y4 = event.pageY-elementTop;

将拖放的图标附加到主要的大图像上:

svg.append("svg:image")
      .attr('xlink:href', 'http://icons.webpatashala.com/icons/Blueberry-Basic-Icons/Png/rss-icon.PNG')
      .attr('x', x1)  //x2, x3, x4, x5
      .attr('y', y1);  //x2, x3, x4, x5

但是使用所有方法,rss图标不会附加在其放置的确切点上。如何获取确切的X和Y值?

jquery d3.js jquery-ui-droppable
1个回答
2
投票

我想我已经知道您要寻找的东西了。对于此问题,需要考虑一些事项:

ViewBox缩放比例

这是要考虑的主要项目。由于您在svg元素上使用viewBox属性,而不在使用width / height,因此无论浏览器窗口大小如何,都会更改svg可见画布的比例。在删除克隆的图像时,必须考虑这一点,因为您不能使用绝对top / left坐标。在0, 0上看起来可能不错,但是当您开始远离它时,您会注意到该图像没有被丢弃在您认为应该的位置。

解决方法是使用d3.scaleLinear()(docs here)。这将有助于将可放置坐标转换为svg的坐标。我汇总的方式是,对于X比例尺,domain从SVG的left属性更改为left + width属性,并且range设置为SVG的视图框x-minwidth值。 Y比例尺使用类似的方法(请参见代码)。

页面上有SVG的地方

这是接下来要考虑的事情。它与有关视图框的上一项一起使用。例如,如果SVG有一些边距,则在设置d3.scaleLinear()标度时需要考虑这一点。这样做的方法是像这样使用getBoundingClientRectangle()

const clientRect = document.getElementById('floor').getBoundingClientRect();

如果调整窗口大小

如果调整窗口大小,则需要重置比例。

您从可拖动元素中获取图像的位置

如果您想弄清楚如何从第一次使用鼠标抓取图像的位置获取x,y偏移量,这会增加一些工作。相反,我在cursorAt方法的配置上使用draggable()属性并将其设置为{ left: 0, top: 0 },因此,当您拖动图像时,用户将在图像的左上方看到光标。这使您无需进行计算图像获取位置的偏移量的工作。

这是我最后使用的代码(pen here)(而且,我不得不使用其他图标,因为所使用的图标没有为我加载)。

let scaleX = getScaleX();
let scaleY = getScaleY();

function getScaleX() {
  const clientRect = document.getElementById('floor').getBoundingClientRect();
  return d3.scaleLinear()
    .domain([clientRect.left, clientRect.left + clientRect.width])
    .range([0, 1500])
}

function getScaleY() {
  const clientRect = document.getElementById('floor').getBoundingClientRect();
  return d3.scaleLinear()
    .domain([clientRect.top, clientRect.top + clientRect.height])
    .range([0, 800])
}

window.onresize = function() {
  scaleX = getScaleX();
  scaleY = getScaleY();
};

var svg = d3.select('#floor');

svg.append("svg:image")
  .attr('xlink:href', 'https://wallpapershome.com/images/pages/pic_h/241.jpg')
  .style('width', "100%");

$(function() {
  $("#draggable" ).draggable({
      helper: "clone",
    cursor: 'move',
    containment: "document",
    cursorAt: { top: 0, left: 0 }
  });

  $( "#droppable" ).droppable({
    drop: function( event, ui ) {
      $( this ).addClass( "ui-state-highlight" );

      svg.append("svg:image")
        .attr('xlink:href', 'https://i2.wp.com/icons.iconarchive.com/icons/cornmanthe3rd/plex/512/Communication-RSS-icon.png')
        .attr('x', scaleX(event.pageX))
        .attr('y', scaleY(event.pageY))
        .attr('width', '50px');
    }
  });
});
© www.soinside.com 2019 - 2024. All rights reserved.