交互式多边形形状

时间:2018-10-14 06:44:51

标签: javascript svg canvas svg.js

我有一些坐标点,例如           [0,0],[30,0],[30,20],[60,20],[60,40],[0,40],[0,0]

将这些点作为输入,需要生成带有可单击角的形状。 边缘彼此重叠。第一次单击时,第一段越过第二段;第二次单击时,第二段越过第一段,第三次单击则产生斜切效果。

Possible Polygon interaction effects 是否可以在角落处放置不透明度为0的矩形以进行点击检测,但是问题是如何检测将矩形放置在角落处的确切位置。

第二,将这些点转换为直线或路径的最佳方法是什么? 生成的线条应足够粗,但不能穿过笔划宽度。

我之前尝试过使用strokewidth进行路径设置,所以行联接斜接无效。 有任何建议请。

示例代码,其中线条和矩形位于拐角处,但由于笔画宽度的缘故,它给我带来的效果并不理想:

<svg id="SvgjsSvg1001" width="700" height="400" xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:svgjs="http://svgjs.com/svgjs" viewBox="-100 -20 350 200"><defs id="SvgjsDefs1002"></defs><g id="SvgjsG1008" transform="matrix(2.5,0,0,2.5,0,0)"><line id="SvgjsLine1009" x1="0" y1="0" x2="30" y2="0" stroke-linecap="square" stroke="#ffdc0b" stroke-width="4"></line><line id="SvgjsLine1010" x1="30" y1="0" x2="30" y2="20" stroke-linecap="square" stroke="#002438" stroke-width="4"></line><line id="SvgjsLine1011" x1="30" y1="20" x2="60" y2="20" stroke-linecap="square" stroke="#9b56bb" stroke-width="4"></line><line id="SvgjsLine1012" x1="60" y1="20" x2="60" y2="40" stroke-linecap="square" stroke="#c6c7e2" stroke-width="4"></line><line id="SvgjsLine1013" x1="60" y1="40" x2="0" y2="40" stroke-linecap="square" stroke="#318700" stroke-width="4"></line><line id="SvgjsLine1014" x1="0" y1="40" x2="0" y2="0" stroke-linecap="square" stroke="#fe854f" stroke-width="4"></line>
<rect width="5" height="5" x="30" y="0"></rect>
<rect width="5" height="5" x="30" y="20"></rect>
<rect width="5" height="5" x="60" y="20"></rect>
<rect width="5" height="5" x="60" y="40"></rect>
<rect width="5" height="5" x="0" y="40"></rect>
<rect width="5" height="5" x="0" y="0"></rect></g></svg>

1 个答案:

答案 0 :(得分:0)

我希望这是您要问的:为了绘制矩形,我正在使用每条路径的边界点。其中两个是重叠的:第一个和最后一个。但这无关紧要,因为您需要鼠标交互。一个失踪了。可以使用包含路径的组的边界框来绘制。

对于鼠标交互,我在每个角落使用cursor: pointer;

const SVG_NS = "http://www.w3.org/2000/svg";
let pathsRy = Array.from(document.querySelectorAll("path"));

let rectsRy = [];

pathsRy.forEach(p => {
  let pbbox = p.getBBox();
  rectsRy.push(
    drawRect(
      {
        x: pbbox.x,
        y: pbbox.y,
        width: 5,
        height: 5,
        class: "corner"
      },
      svg
    )
  );
});

let gbbox = group.getBBox();
rectsRy.push(
  drawRect(
    {
      x: gbbox.x + gbbox.width - 5,
      y: gbbox.y + gbbox.height - 5,
      width: 5,
      height: 5,
      class: "corner"
    },
    svg
  )
);

function drawRect(o, parent) {
  var rect = document.createElementNS(SVG_NS, "rect");
  for (var name in o) {
    if (o.hasOwnProperty(name)) {
      rect.setAttributeNS(null, name, o[name]);
    }
  }
  parent.appendChild(rect);
  return rect;
}
.corner {
  fill: rgba(255, 0, 0, 0.5);
  cursor: pointer;
}

svg {
  overflow: visible;
}

path {
  fill: none;
  stroke: black;
  stroke-linejoin: round;
}
<svg id="svg" viewBox="0 0 70 70" width="200" >
<g id="group">  
  <path d="M0,0 L30,0 25,5 5,5z" /> 
           
  <path d="M30,0 L30,20 25,25 25,5z" /> 
  
  <path d="M30,20 L60,20 55,25 25,25" />
  
  <path d="M60,20 L60,40 55,35 55,25" /> 
  
  <path d="M60,40 L0,40 5,35 55,35z" />
           
  <path d="M0,40 L0,0 5,5 5,35z" />
  </g>
</svg>

请注意,这适用于这种形状。对于具有多个“转折点”且处于不同位置的形状,它将不起作用。

更新
  1. 我弄清了您的代码。由于所有行都具有相同的stroke-linecap,因此将其放在SVG中。另外,由于我需要在JavaScript中移动stroke-width,因此也要在其中使用它。

  2. 在Java语言中,我定义了行数组linesRy。对于每一行,我都得到x1和y1属性的值。

  3. 使用每行和stroke-width的x1和y1属性的值的值,我在每个角上绘制了一个粉红色的rect

OP更新了发布一些代码的问题。我也在更新代码:

const SVG_NS = "http://www.w3.org/2000/svg";

let strokeWidth = 4

let linesRy = Array.from(document.querySelectorAll("line"));

linesRy.forEach((l)=>{
  l.setAttributeNS(null, "stroke-width", strokeWidth);
  let x = l.getAttribute("x1");
  let y = l.getAttribute("y1");
  
  drawRect({
    x:x-strokeWidth/2,
    y:y-strokeWidth/2,
    width:strokeWidth,
    height:strokeWidth,
    class:"pink"
  }, SvgjsG1008);
})


function drawRect(o, parent) {
  var rect = document.createElementNS(SVG_NS, "rect");
  for (var name in o) {
    if (o.hasOwnProperty(name)) {
      rect.setAttributeNS(null, name, o[name]);
    }
  }
  parent.appendChild(rect);
  return rect;
}
line{
stroke-linecap:square;
}

.pink{fill:pink}
<svg id="SvgjsSvg1001" width="700" height="400" viewBox="-100 -20 350 200">
<g id="SvgjsG1008" transform="matrix(2.5,0,0,2.5,0,0)"><line id="SvgjsLine1009" x1="0" y1="0" x2="30" y2="0"  stroke="#ffdc0b" ></line>
  
<line id="SvgjsLine1010" x1="30" y1="0" x2="30" y2="20" stroke="#002438"></line>

<line id="SvgjsLine1011" x1="30" y1="20" x2="60" y2="20" stroke="#9b56bb"></line>
  
<line id="SvgjsLine1012" x1="60" y1="20" x2="60" y2="40" stroke="#c6c7e2"></line>
   
<line id="SvgjsLine1013" x1="60" y1="40" x2="0" y2="40"  stroke="#318700" ></line>

<line id="SvgjsLine1014" x1="0" y1="40" x2="0" y2="0" stroke="#fe854f" ></line>
  
  
  
<!--  
<rect width="5" height="5" x="30" y="0"></rect>
<rect width="5" height="5" x="30" y="20"></rect>
<rect width="5" height="5" x="60" y="20"></rect>
<rect width="5" height="5" x="60" y="40"></rect>
<rect width="5" height="5" x="0" y="40"></rect>
<rect width="5" height="5" x="0" y="0"></rect>-->

</g></svg>