交互式多边形形状
Interactive polygon shapes
我有一些坐标点
[0, 0],[30, 0],[30, 20],[60, 20],[60, 40],[0, 40],[0, 0]
将这些点作为输入,需要生成带有可点击角的形状。
边缘重叠在每个 other.On 第一次鼠标点击上,第一段超过 second.On 第二次点击,第二段第一次超过,第三次点击它产生斜接效果。
[可能的多边形交互效果][1]
[1]: https://i.stack.imgur.com/Ok0iM.png
我可以在拐角处放置一个不透明度为 0 的矩形以进行点击检测吗,但问题是如何检测将矩形放置在拐角处的确切位置。
其次,将这些点转换为线或路径的最佳方式是什么?。
生成的线条应该足够粗但不能超过 strokewidth。
我之前尝试过使用 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.dev/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>
我希望这就是您要问的:为了绘制角矩形,我使用了每条路径的边界框。其中两个重叠:第一个和最后一个。但这并不重要,因为您需要鼠标交互。一个不见了。这可以通过使用包含您的路径的组的边界框来绘制。
对于鼠标交互,我在每个角落使用 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>
请注意,这适用于这种形状。对于具有多个“转折点”且位置不同的形状,它不起作用。
更新
我整理了你的代码。由于所有行都具有相同的 stroke-linecap
我将其放入 SVG 中。此外,我正在将 stroke-width
移动到 JavaScript 中,因为我在那里需要它。
在Javascript中我定义了行数组linesRy
。对于每一行,我都得到 x1 和 y1 属性的值。
使用每一行的 x1 和 y1 属性的值和 stroke-width
我在每个角上画一个粉红色 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>
我有一些坐标点 [0, 0],[30, 0],[30, 20],[60, 20],[60, 40],[0, 40],[0, 0]
将这些点作为输入,需要生成带有可点击角的形状。 边缘重叠在每个 other.On 第一次鼠标点击上,第一段超过 second.On 第二次点击,第二段第一次超过,第三次点击它产生斜接效果。
[可能的多边形交互效果][1] [1]: https://i.stack.imgur.com/Ok0iM.png
我可以在拐角处放置一个不透明度为 0 的矩形以进行点击检测吗,但问题是如何检测将矩形放置在拐角处的确切位置。
其次,将这些点转换为线或路径的最佳方式是什么?。 生成的线条应该足够粗但不能超过 strokewidth。
我之前尝试过使用 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.dev/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>
我希望这就是您要问的:为了绘制角矩形,我使用了每条路径的边界框。其中两个重叠:第一个和最后一个。但这并不重要,因为您需要鼠标交互。一个不见了。这可以通过使用包含您的路径的组的边界框来绘制。
对于鼠标交互,我在每个角落使用 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>
请注意,这适用于这种形状。对于具有多个“转折点”且位置不同的形状,它不起作用。
更新我整理了你的代码。由于所有行都具有相同的
stroke-linecap
我将其放入 SVG 中。此外,我正在将stroke-width
移动到 JavaScript 中,因为我在那里需要它。在Javascript中我定义了行数组
linesRy
。对于每一行,我都得到 x1 和 y1 属性的值。使用每一行的 x1 和 y1 属性的值和
stroke-width
我在每个角上画一个粉红色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>