我可以在浏览器中选择 SVG 元素吗?

AFF*_*AFF 1 browser svg selection

我正在尝试编写一个图形网格编辑器,并且正在研究使用 SVG 绘制网格的可能性,希望有一些可以选择网格元素。因此,SVG 网格将由按列和行排列的彩色矩形组成。用户可以通过给不同的矩形涂上不同的颜色来绘制数字图片。

我可以轻松绘制 svg 矩形网格,并且显示效果很好。但我希望用户能够从 svg 显示中选择一组矩形。因此,也许他们想要通过用鼠标拖动矩形区域并选择它们来选择多个矩形,然后他们可能想要为所有特定颜色着色。

有没有办法让浏览器显示对网格中显示的矩形子集的选择?或者说 SVG 不可能做到这一点?我是 SVG 新手,所以以前从未使用过它。我的简单网格测试,用鼠标拖动 svg 矩形元素时不显示任何选择。

有一些简单的方法可以做到这一点吗?

或者,我认为我需要使用 HTML 5 画布来显示并自己处理所有鼠标事件。

enx*_*eta 5

我就是这样做的:

  1. 我创建网格并将矩形保存在rects数组中。

  2. min_x按下鼠标时,我更改和变量的值min_y

  3. max_x鼠标松开时,我更改和的值max_y,并过滤rects数组以更改所选范围内矩形的颜色:

         x >= min_x-size &&
         y >= min_y-size &&
         x <= max_x &&
         y <= max_y
    
    Run Code Online (Sandbox Code Playgroud)

这是一个例子。请在 svg 画布上单击并拖动。

     x >= min_x-size &&
     y >= min_y-size &&
     x <= max_x &&
     y <= max_y
Run Code Online (Sandbox Code Playgroud)
let SVG_NS = svg.namespaceURI;
let size = 10;// the size of a grid cell
let w = 100;//the width of the grid
let h = 100;//the height of the grid
let rectx=0,recty=0;

let selecting = false;

// the rects array
let rects = []; 

//create the grid.Push the new rect into the rects array. All the recta have a fill attribute 
for(let y = 0; y< h; y+=size){
for(let x = 0; x < w; x+=size){
    let rect = drawSVGelmt({x:x,y:y,width:size,height:size,fill:"white"},"rect", svgG);
    rects.push(rect)
}
}

let min_x = 0,max_x=100,min_y=0,max_y = 100


//on mouse down change the value of the min_x and min_y
svg.addEventListener("mousedown",(e)=>{
  selecting = true
  m = oMousePosSVG(e,svg)
  min_x = m.x,min_y=m.y;
  rectx = m.x;
  recty = m.y;
  selector.setAttributeNS(null,"x",rectx);
  selector.setAttributeNS(null,"y",recty);
})

//on mouse up change the value of the max_x and max_y, filter the rects array and change the color of the "selected" rects

svg.addEventListener("mousemove",(e)=>{
  if(selecting){
  m = oMousePosSVG(e,svg);
  selector.setAttributeNS(null,"width",m.x-rectx);
  selector.setAttributeNS(null,"height",m.y-recty);
  }
});



svg.addEventListener("mouseup",(e)=>{
  if(selecting){
  let m = oMousePosSVG(e,svg)
  max_x = m.x,max_y=m.y;
  selector.setAttributeNS(null,"x",0);
  selector.setAttributeNS(null,"y",0);
  selector.setAttributeNS(null,"width",0);
  selector.setAttributeNS(null,"height",0);
  
  rects.filter((el)=> {
  let x = el.getAttribute("x");
  let y = el.getAttribute("y");
     if (x >= min_x-size &&
         y >= min_y-size &&
         x <= max_x &&
         y <= max_y){
       el.setAttribute("fill","red")}
});
  
  }
  
  selecting = false;
})



// a function to draw a new svg element
function drawSVGelmt(o,tag, parent) {
  
  let elmt = document.createElementNS(SVG_NS, tag);
  for (let name in o) {
    if (o.hasOwnProperty(name)) {
      elmt.setAttributeNS(null, name, o[name]);
    }
  }
  parent.appendChild(elmt);
  return elmt;
}

// a function to detect the mouse position on the svg canvas
function oMousePosSVG(e, svg) {
  var p = svg.createSVGPoint();
  p.x = e.clientX;
  p.y = e.clientY;
  var ctm = svg.getScreenCTM().inverse();
  var p = p.matrixTransform(ctm);
  return p;
}
Run Code Online (Sandbox Code Playgroud)
svg{border:1px solid; width:90vh;}
rect{stroke:black; vector-effect:non-scaling-stroke;pointer-events:all}
Run Code Online (Sandbox Code Playgroud)