Javascript 如何在drawnrect d3中选择svg对象

Javascript 如何在drawnrect d3中选择svg对象,javascript,asp.net-mvc,d3.js,Javascript,Asp.net Mvc,D3.js,我正在创建一个小的图形编辑器,用户(现在)可以在其中插入一些“符号”,这些符号由一些svg元素组成,分组在一个g标签中。 此外,他还可以用不同的颜色画线 现在我可以选择单个绘制的线条和符号,也可以在按住控制键的同时单击它们来选择更多的对象。(对于那些与之相关的对象,一个选定对象会得到一个类“selected”,因此我可以通过d3.select('.selected')以编程方式找到它们) 我的新目标是用鼠标在这些元素上画一个矩形,然后选择矩形内的元素。 为此,我捕获pointerdown事件,在


我正在创建一个小的图形编辑器,用户(现在)可以在其中插入一些“符号”,这些符号由一些svg元素组成,分组在一个g标签中。
此外,他还可以用不同的颜色画线

现在我可以选择单个绘制的线条和符号,也可以在按住控制键的同时单击它们来选择更多的对象。(对于那些与之相关的对象,一个选定对象会得到一个类“selected”,因此我可以通过
d3.select('.selected')
以编程方式找到它们)

我的新目标是用鼠标在这些元素上画一个矩形,然后选择矩形内的元素。
为此,我捕获pointerdown事件,在该事件中,我向svg框添加一个矩形,并在pointermove事件中缩放它。
附件,一个简单的视频我的实际版本

我现在有两个问题:

1) 当按下鼠标左键移动时,如何避免元素像选定的文本一样高置?(您可以在视频中看到闪烁)
是否有类似于
event.preventDefault()的内容要这样做吗

2) …这是更大的问题…
绘制矩形是一种很好的方法吗?如何快速计算出矩形中的元素?d3中是否有一个我还没有找到的特殊函数

编辑:为了澄清,我附上了一个符号和一行的svg结构截图:

代码笔示例:

补充问题:
svg_children[i]之间的区别是什么

svg_子项[i].classList.add('selected')

我遇到了一些问题,baseVal似乎没有存储在dom中?如果这样使用,我在开发者窗口的元素窗格中看不到该类,但它会在符号处弹出。如果我使用ClassList.add,我也可以在元素窗格中看到该类。
屏幕截图:
如您所见,黄色标记的类似乎在弹出窗口中,而不是在元素代码中。这是通过
svg_children[i]添加的
红色标记的“选定”类是由
svg\u子类[i].classList.add(“选定”)添加的。


到目前为止,非常感谢,
Carsten

我想我为您提供了一个解决方案,使用svg元素的
.getClientBoundingRect()
来确定您的框是否与它们重叠,等等

演示-:

代码:

然后,我创建了一个函数,用于测试长方体是否与元素边界框的至少一个角重叠:

function elementIsInside(el, box){
var result = false;
  el_rect = el.getBoundingClientRect();
  box_rect = box.getBoundingClientRect();
  // console.log("rects_" + el.tagName, el_rect, box_rect)
  // console.log("rects_" + el.tagName, el, box)
  if (el_rect.right >= box_rect.left && el_rect.right <= box_rect.right
     && el_rect.bottom >= box_rect.top && el_rect.bottom <= box_rect.bottom){
    result = true;
  } else if (el_rect.left >= box_rect.left && el_rect.left <= box_rect.right
     && el_rect.bottom >= box_rect.top && el_rect.bottom <= box_rect.bottom){
    result = true;
  } else if (el_rect.right >= box_rect.left && el_rect.right <= box_rect.right
     && el_rect.top >= box_rect.top && el_rect.top <= box_rect.bottom){
    result = true;
  } else if (el_rect.left >= box_rect.left && el_rect.left <= box_rect.right
     && el_rect.top >= box_rect.top && el_rect.top <= box_rect.bottom){
    result = true;
  }
  // console.log("result_" + el.tagName, result)
  return result;
}
功能元件集成(el,方框){
var结果=假;
el_rect=el.getBoundingClientRect();
box_rect=box.getBoundingClientRect();
//console.log(“rects\u”+el.tagName,el\u rect,box\u rect)
//console.log(“rects_u”+el.tagName,el,box)

如果(elu-rect.right>=box-rect.left&&elu-rect.right=box-rect.top&&elu-rect.bottom=box-rect.left&&elu-rect.left=box-rect.top&&elu-rect.bottom=box-rect.left&&elu-rect.right=box-rect.top&&elu-rect.top=box-rect.left&&elu-rect.top=box-rect.left&&elu-rect.top=box-rect.top=box-rect.top=box-left&elu-rect.top=box-rect.top&elu-rect.top=box-rect.top=box-rect.top&elu-rect.top=box-recc、 嗯…我不知道你到底想看什么?当然我可以创建一些简化的示例,但你希望看到什么?一般来说,在代码笔类型的沙盒中查看一个简化的示例并以这种方式解决是最好的-即使它是你的应用程序的简化或匿名版本,那么我们可以提供一个具体的答案。如果你添加真实的代码然后我们知道您到目前为止尝试了什么,可以复制它,可以测试它,可以解决它。我会尽我最大的努力,只花一个小时左右。我没有让Java在codepen上运行。为什么这在codepen中不起作用?:
$(document.ready(function(){console.log(“hier”);})
https://code.jquery.com/jquery-2.2.4.min.js
已经添加。看起来很酷。我需要一些时间来理解,但首先,您将e参数传递给了事件。我没有这样做,而且效果很好。有什么不同吗?在我完全理解您所做的事情后,我会带着新问题回来。啊,似乎是evENT参数是隐式传递的,我总是明确地传递它,但是这个答案表明你不需要:-很高兴听到你喜欢我的答案。如果你喜欢它和/或它帮助你,请考虑将它标记为正确答案并进行投票。期待听到任何问题。我需要选择一个完整的符号。(嵌套在g标记中,分类为“preview”,因此此示例对运行此操作非常有帮助。对于符号选择,我只需将svg_children-selection更改为document.getElementsByClassName('preview')。谢谢,CarstenYou应该使用
.classList.add()
如果它对您有效。这是首选方法,但在codePen中,我出现了错误,例如“无法调用.add method of null”,当我检查元素时,它们具有类的对象而不是简单的字符串。类似于
{baseVal:“some class”,AnimVal:“some class”}
所以我想这是你设置的。比如基类和动画类。它们应该只在使用
时出现-我也有点困惑,因为我在你的HTML中没有看到这些动画标记。因此,
.classList.add()
如果可能的话肯定是最好的方法:)
var svgDrawing = document.getElementById('drawing');
var pointerOrigin;
var point = svgDrawing.createSVGPoint();
var drawRectToSelect
var raster = 10;

$(document).ready(function () {
  svgDrawing = document.getElementById('drawing');
  svg_rect = svgDrawing.getBoundingClientRect();
  console.log("svg_rect", svg_rect);
  g = document.getElementById("437");
  //svg_children = g.childNodes;
  svg_children = g.querySelectorAll("*");
  console.log(svg_children);
  svgDrawing.addEventListener('pointerdown', e => mouseButtonPressed(e));
  svgDrawing.addEventListener('pointerup', e => mouseButtonReleased(e));
  svgDrawing.addEventListener('pointermove', e => mouseMove(e));
})

function mouseButtonPressed(evt) {
  pointerOrigin = getPointFromEvent(evt);
  if(evt.button === 0)
    {
      drawRectToSelect = d3.select('#drawing')
      .append('rect')
      .attr("id","temp_selection")
      .classed('selectionBox', true)
      .attr("x", Math.round(pointerOrigin.x / raster) * raster)
            .attr("y", Math.round(pointerOrigin.y / raster) * raster)
            .attr("height", raster)
            .attr("width", raster);
    }
}

function mouseMove(evt) {
    if (!drawRectToSelect) { return; }

    evt.preventDefault();  //Verschieben der gesamten Seite unterbinden

    var pointerPosition = getPointFromEvent(evt);
    if (drawRectToSelect) {
        drawRectToSelect
            .attr("width", Math.round((pointerPosition.x - pointerOrigin.x) / raster) * raster)
            .attr("height", Math.round((pointerPosition.y - pointerOrigin.y) / raster) * raster);
    }
}

function elementIsInside(el, box){
  var result = false;
  el_rect = el.getBoundingClientRect();
  box_rect = box.getBoundingClientRect();
  // console.log("rects_" + el.tagName, el_rect, box_rect)
  // console.log("rects_" + el.tagName, el, box)
  if (el_rect.right >= box_rect.left && el_rect.right <= box_rect.right
     && el_rect.bottom >= box_rect.top && el_rect.bottom <= box_rect.bottom){
    result = true;
  } else if (el_rect.left >= box_rect.left && el_rect.left <= box_rect.right
     && el_rect.bottom >= box_rect.top && el_rect.bottom <= box_rect.bottom){
    result = true;
  } else if (el_rect.right >= box_rect.left && el_rect.right <= box_rect.right
     && el_rect.top >= box_rect.top && el_rect.top <= box_rect.bottom){
    result = true;
  } else if (el_rect.left >= box_rect.left && el_rect.left <= box_rect.right
     && el_rect.top >= box_rect.top && el_rect.top <= box_rect.bottom){
    result = true;
  }
  // console.log("result_" + el.tagName, result)
  return result;
}

function mouseButtonReleased(evt) {
    svgDrawing.style.cursor = null;

    if (drawRectToSelect) {
      const box = document.querySelector('#temp_selection');
      for (i=0; i < svg_children.length; i++){
        //svg_children[i].classList.add("selected");
        console.log(svg_children[i].tagName)
        console.log(svg_children[i].className.baseVal)
        child_rect = svg_children[i].getBoundingClientRect();
        console.log(child_rect);        

        //calculate elements inside rectangle
        if (elementIsInside(svg_children[i], box )){
          if (svg_children[i].className.baseVal.includes('selected')){

          } else {
            svg_children[i].className.baseVal += " selected";
            svg_children[i].className.animVal += " selected";
          }
        } else {          
          if (svg_children[i].className.baseVal.includes('selected')){
            console.log("true")
            svg_children[i].className.baseVal = svg_children[i].className.baseVal.replace(" selected"," ");
            svg_children[i].className.animVal = svg_children[i].className.animVal.replace(" selected"," ");
            console.log(svg_children[i].className.baseVal);
          } else {
            console.log("false")
            console.log(svg_children[i].className.baseVal);
          }
        }              
      }                  
      //Delete selection-rectangle
      drawRectToSelect.remove();
      drawRectToSelect = null;
    }
}

function getPointFromEvent(evt) {
    if (evt.targetTouches) {
        point.x = evt.targetTouches[0].clientX;
        point.y = evt.targetTouches[0].clientY;
    } else {
        point.x = evt.clientX;
        point.y = evt.clientY;
    }
    var invertedSVGMatrix = svgDrawing.getScreenCTM().inverse();

    return point.matrixTransform(invertedSVGMatrix);
}
$(document).ready(function () {
  svgDrawing = document.getElementById('drawing');
  svg_rect = svgDrawing.getBoundingClientRect();
  console.log("svg_rect", svg_rect);
  g = document.getElementById("437");
  //svg_children = g.childNodes;
  svg_children = g.querySelectorAll("*");
  console.log(svg_children);
  svgDrawing.addEventListener('pointerdown', e => mouseButtonPressed(e));
  svgDrawing.addEventListener('pointerup', e => mouseButtonReleased(e));
  svgDrawing.addEventListener('pointermove', e => mouseMove(e));
})
function elementIsInside(el, box){
var result = false;
  el_rect = el.getBoundingClientRect();
  box_rect = box.getBoundingClientRect();
  // console.log("rects_" + el.tagName, el_rect, box_rect)
  // console.log("rects_" + el.tagName, el, box)
  if (el_rect.right >= box_rect.left && el_rect.right <= box_rect.right
     && el_rect.bottom >= box_rect.top && el_rect.bottom <= box_rect.bottom){
    result = true;
  } else if (el_rect.left >= box_rect.left && el_rect.left <= box_rect.right
     && el_rect.bottom >= box_rect.top && el_rect.bottom <= box_rect.bottom){
    result = true;
  } else if (el_rect.right >= box_rect.left && el_rect.right <= box_rect.right
     && el_rect.top >= box_rect.top && el_rect.top <= box_rect.bottom){
    result = true;
  } else if (el_rect.left >= box_rect.left && el_rect.left <= box_rect.right
     && el_rect.top >= box_rect.top && el_rect.top <= box_rect.bottom){
    result = true;
  }
  // console.log("result_" + el.tagName, result)
  return result;
}
function mouseButtonReleased(evt) {
    svgDrawing.style.cursor = null;

    if (drawRectToSelect) {
      const box = document.querySelector('#temp_selection');
      for (i=0; i < svg_children.length; i++){
        //svg_children[i].classList.add("selected");
        console.log(svg_children[i].tagName)
        console.log(svg_children[i].className.baseVal)
        child_rect = svg_children[i].getBoundingClientRect();
        console.log(child_rect);        

        //calculate elements inside rectangle
        if (elementIsInside(svg_children[i], box )){
          if (svg_children[i].className.baseVal.includes('selected')){

          } else {
            svg_children[i].className.baseVal += " selected";
            svg_children[i].className.animVal += " selected";
          }
        } else {          
          if (svg_children[i].className.baseVal.includes('selected')){
            console.log("true")
            svg_children[i].className.baseVal = svg_children[i].className.baseVal.replace(" selected"," ");
            svg_children[i].className.animVal = svg_children[i].className.animVal.replace(" selected"," ");
            console.log(svg_children[i].className.baseVal);
          } else {
            console.log("false")
            console.log(svg_children[i].className.baseVal);
          }
        }              
      }                  
      //Delete selection-rectangle
      drawRectToSelect.remove();
      drawRectToSelect = null;
    }
}