javascript - 获取 2 条或多条路径相交的边界框
问题描述
在下面的示例中,我有 3 个形状的交点(在本例中,我使用的是圆形,但这 3 个形状可以是任何形状) 黄金交点是使用剪辑路径进行剪辑的结果。
我想使用交叉点作为符号,为此我需要知道交叉点的边界框,即红色描边矩形。
如果我使用intersection.getBBox() 我会在剪裁之前得到边界框。
如何获得交叉点的边界框?
console.log(intersection.getBBox())
svg{border:solid}
.circles{fill:none;stroke:black}
<svg id="svg" viewBox="-150 -150 300 300" width="300">
<defs>
<circle id="c1" cx="0" cy="-50" r="80"></circle>
<circle id="c2" cx="43.3" cy="25" r="80"></circle>
<circle id="c3" cx="-43.3" cy="25" r="80"></circle>
<clipPath id="clipC2"><use xlink:href="#c2"/></clipPath>
<clipPath id="clipC3"><use xlink:href="#c3"/></clipPath>
</defs>
<g class="circles">
<use xlink:href="#c1"/>
<use xlink:href="#c2"/>
<use xlink:href="#c3"/>
</g>
<g id="intersection">
<g clip-path="url(#clipC3)">
<use fill="gold" xlink:href="#c1" clip-path="url(#clipC2)"/>
</g>
</g>
<rect x="-38" y="-42" width="75" height="74" stroke="red" fill="none"/>
</svg>
解决方案
主要思想是这样的:
- 我正在使用 svg 元素,将其设为 base64 并将其用作
src
图像的属性。 - 我将 svg 元素绘制在与 svg 元素
canvas
大小相同的 a 上。 - 我从画布中获取图像数据
- 遍历图像数据并获得:
- 黑色像素的最小 x 值
- 黑色像素的最小 y 值
- 黑色像素的最大 x 值
- 黑色像素的最大y值
- 我正在使用这些值来为交叉点构建新的 viewBox 值。
//the svg's viewBox
let vB = { x: -100, y: -100, w: 200, h: 200 };
//canvas
let ctx = c.getContext("2d");
//set the size of the canvas equal to the size of the svg element
c.width = vB.w;
c.height = vB.h;
// draw the svg element on the canvas
let xml = new XMLSerializer().serializeToString(svg);
// make it base64 and use it as the src attribute of the image
let img=new Image()
img.src = "data:image/svg+xml;base64," + btoa(xml);
img.onload = function() {
//paint the image on the canvas
ctx.drawImage(this, 0, 0);
//get the image data from the canvas
let imgData = ctx.getImageData(0, 0, vB.w, vB.h).data;
// x the smallest x value of a black pixel
// y the smallest y value of a black pixel
// X the biggest x value of a black pixel
// Y the biggest y value of a black pixel
let x = vB.w,
y = vB.h,
X = 0,
Y = 0;
let n = 0;
for (let i = 0; i < imgData.length; i += 4) {
n++
if (imgData[i + 3] != 0) {
//if the alpha (i+3) value of the pixel is not 0
let _y = Math.ceil(i / (4 * vB.w));
let _x = (i / 4) % vB.w;
if (_x < x) { x = _x; }
if (_y < y) { y = _y; }
if (_x > X) { X = _x; }
if (_y > Y) { Y = _y; }
}
if(n==imgData.length/4){
let newViewBox = `${x + vB.x} ${y + vB.y} ${X - x + 1} ${Y - y}`;
reuleaux.setAttribute("viewBox", newViewBox);
console.log(`viewBox="${newViewBox}"`);
}
}
}
svg,
canvas {
outline: 1px solid;
}
<svg id="svg" viewBox="-100 -100 200 200" width="200">
<defs>
<circle id="c1" cx="0" cy="-50" r="80"></circle>
<circle id="c2" cx="43.3" cy="25" r="80"></circle>
<circle id="c3" cx="-43.3" cy="25" r="80"></circle>
<clipPath id="clipC2"><use xlink:href="#c2"/></clipPath>
<clipPath id="clipC3"><use xlink:href="#c3"/></clipPath>
</defs>
<g id="intersection">
<g clip-path="url(#clipC3)">
<use xlink:href="#c1" clip-path="url(#clipC2)"/>
</g>
</g>
</svg>
<!--<img id="img" width="200" height="200"/>-->
<canvas id="c"></canvas>
<svg id="reuleaux" viewBox="-100 -100 200 200" width="200" style="background:#dfdfdf">
<use xlink:href="#intersection"/>
</svg>
推荐阅读
- python - Heroku Procfile 与多个工人
- rust - 使用 Rust/git2 将远程拉入本地分支
- docker - 通过 docker-compose 和环境变量将单个文件复制到容器中
- reactjs - ReactJS 中的映射方法
- javascript - 调用 setState 时组件重新渲染
- python - 在 AWS 上使用私有 ip 运行的 Flask 服务器
- html - 强制图像元素填充所有可用空间
- python - 获取 Slack 中所有公共和私人频道的列表
- javascript - JSON 类型 NSMutableDictionary 不能转换为 .sdp 不能为空
- laravel - Laravel 测试假事件