gpt4 book ai didi

javascript - venn.js 选择 Set[A] 除了 Set[B]

转载 作者:行者123 更新时间:2023-11-29 14:42:00 29 4
gpt4 key购买 nike

我有这个代码:

var sets = [
{sets: ['A'], size: 10},
{sets: ['B'], size: 10},
{sets: ['A','B'], size: 5}
];

var chart = venn.VennDiagram();
var div = d3.select("#venn").datum(sets).call(chart);

使用优秀 venn.js图书馆,我的维恩图已经绘制完成,效果很好。

使用此代码:

            div.selectAll("g")
.on("mouseover", function (d, i) {
// sort all the areas relative to the current item
venn.sortAreas(div, d);

// Display a tooltip with the current size
tooltip.transition().duration(400).style("opacity", .9);
tooltip.text(d.size + " items");

// highlight the current path
var selection = d3.select(this).transition("tooltip").duration(400);
selection.select("path")
.style("stroke-width", 3)
.style("fill-opacity", d.sets.length == 1 ? .4 : .1)
.style("stroke-opacity", 1)
.style("cursor", "pointer");
})

.on("mousemove", function () {
tooltip.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px");
})

.on("click", function (d, i) {
window.location.href = "/somepage"
})

.on("mouseout", function (d, i) {
tooltip.transition().duration(400).style("opacity", 0);
var selection = d3.select(this).transition("tooltip").duration(400);
selection.select("path")
.style("stroke-width", 1)
.style("fill-opacity", d.sets.length == 1 ? .25 : .0)
.style("stroke-opacity", 0);
});

我能够为我的 venn 添加点击、鼠标悬停等功能。

问题是:

向圈子(集合 A 或 B)添加功能效果很好。

向交集添加功能(集合 A 与集合 B 相交)效果很好。

我需要给Except Area(set A except set B)添加一些功能

这个问题有点帮助:2D Polygon Boolean Operations with D3.js SVG

但我没能成功。

尝试找出除区域外使用:clipperjsGreiner-Hormann polygon clipping algorithm但无法让它发挥作用。

更新 1:

本题代码复制自venn.js示例:http://benfred.github.io/venn.js/examples/intersection_tooltip.html

其他样本: https://github.com/benfred/venn.js/

最佳答案

也许你可以做这样的事情......

给定 2 个重叠的圆圈,

  • 找到两个交点,并
  • 手动创建一条路径,从 IP1 沿着圆 A 到 IP2,然后从 IP2 沿着圆 B 回到 IP1。

创建该路径(涵盖 A,不包括 B)后,您可以根据需要设置样式并将点击事件(等)添加到该 SVG 路径元素。

查找交点(IP)

Circle-circle intersection points

var getIntersectionPoints = function(circleA, circleB){

var x1 = circleA.cx,
y1 = circleA.cy,
r1 = circleA.r,
x2 = circleB.cx,
y2 = circleB.cy,
r2 = circleB.r;

var d = Math.sqrt(Math.pow(x2-x1,2)+Math.pow(y2-y1,2)),
a = (Math.pow(r1,2)-Math.pow(r2,2)+Math.pow(d,2))/(2*d),
h = Math.sqrt(Math.pow(r1,2)-Math.pow(a,2));

var MPx = x1 + a*(x2-x1)/d,
MPy = y1 + a*(y2-y1)/d,
IP1x = MPx + h*(y2-y1)/d,
IP1y = MPy - h*(x2-x1)/d,
IP2x = MPx - h*(y2-y1)/d,
IP2y = MPy + h*(x2-x1)/d;

return [{x:IP1x,y:IP1y},{x:IP2x,y:IP2y}]

}

手动创建路径

var getExclusionPath = function(keepCircle, excludeCircle){

IPs = getIntersectionPoints(keepCircle, excludeCircle);

var start = `M ${IPs[0].x},${IPs[0].y}`,
arc1 = `A ${keepCircle.r},${keepCircle.r},0,1,0,${IPs[1].x},${IPs[1].y}`,
arc2 = `A ${excludeCircle.r},${excludeCircle.r},0,0,1,${IPs[0].x},${IPs[0].y}`,
pathStr = start+' '+arc1+' '+arc2;

return pathStr;

}

var height = 900;
width = 1600;

d3.select(".plot-div").append("svg")
.attr("class", "plot-svg")
.attr("width", "100%")
.attr("viewBox", "0 0 1600 900")

var addCirc = function(circ, color){
d3.select(".plot-svg").append("circle")
.attr("cx", circ.cx)
.attr("cy", circ.cy)
.attr("r", circ.r)
.attr("fill", color)
.attr("opacity", "0.5")
}

var getIntersectionPoints = function(circleA, circleB){

var x1 = circleA.cx,
y1 = circleA.cy,
r1 = circleA.r,
x2 = circleB.cx,
y2 = circleB.cy,
r2 = circleB.r;

var d = Math.sqrt(Math.pow(x2-x1,2)+Math.pow(y2-y1,2)),
a = (Math.pow(r1,2)-Math.pow(r2,2)+Math.pow(d,2))/(2*d),
h = Math.sqrt(Math.pow(r1,2)-Math.pow(a,2));

var MPx = x1 + a*(x2-x1)/d,
MPy = y1 + a*(y2-y1)/d,
IP1x = MPx + h*(y2-y1)/d,
IP1y = MPy - h*(x2-x1)/d,
IP2x = MPx - h*(y2-y1)/d,
IP2y = MPy + h*(x2-x1)/d;

return [{x:IP1x,y:IP1y},{x:IP2x,y:IP2y}]

}

var getExclusionPath = function(keepCircle, excludeCircle){

IPs = getIntersectionPoints(keepCircle, excludeCircle);

var start = `M ${IPs[0].x},${IPs[0].y}`,
arc1 = `A ${keepCircle.r},${keepCircle.r},0,1,0,${IPs[1].x},${IPs[1].y}`,
arc2 = `A ${excludeCircle.r},${excludeCircle.r},0,0,1,${IPs[0].x},${IPs[0].y}`,
pathStr = start+' '+arc1+' '+arc2;

return pathStr;

}



var circleA = {cx: 600, cy: 500, r: 400};
var circleB = {cx: 900, cy: 400, r: 300};

var pathStr = getExclusionPath(circleA, circleB)

addCirc(circleA, "steelblue");
addCirc(circleB, "darkseagreen");

d3.select(".plot-svg").append("text")
.text("Hover over blue circle")
.attr("font-size", 70)
.attr("x", 30)
.attr("y", 70)

d3.select(".plot-svg").append("path")
.attr("class","exlPath")
.attr("d", pathStr)
.attr("stroke","steelblue")
.attr("stroke-width","10")
.attr("fill","white")
.attr("opacity",0)
.plot-div{
width: 50%;
display: block;
margin: auto;
}

.plot-svg {
border-style: solid;
border-width: 1px;
border-color: green;
}

.exlPath:hover {
opacity: 0.7;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

<div class="plot-div">

</div>

如果您的维恩图中有更复杂的重叠(超过 3 个区域重叠),那么这显然会变得更加复杂,但我认为您仍然可以针对这些情况扩展此方法。

快速(有点)注意处理 3 组交叉点,即。 A∩B\C或A∩B∩C

A∩B和圆C有3个“层次”的重叠……

  • 完全包含在 C | 两个AB IP都在C
  • 部分重叠; C“切穿”A∩B | C中只有一个AB IP
  • A∩B完全在C之外| C 中没有 AB IP

注意:这是假设 C 不是 A 或 B 的子集或完全包含在其中——否则,例如,两个 BC IP 都可能包含在 A 中

您总共需要 3 个点来为 3 个重叠的圆圈创建路径。前 2 个沿着 C,它“穿过”A∩B。那些是……

  1. A包含的BC交点
  2. B包含的AC交点

对于路径的第 3 个点,这取决于你想要 (i)A∩B∩C 还是 (ii)A∩B\C...

  1. (i) A∩B∩C:C包含的AB交点

    (ii) A∩B\C:AB交点包含在C

有了这些点,您可以用适当的弧线手动绘制路径。


奖励 -- 获取 2 个圈子的任何子部分

同样值得注意的是,您可以通过选择正确的 large-arc-flagsweep-flag 来获得任何子部分。聪明地挑选,你会得到...

  1. 圈A(作为路径)
  2. 圆圈 B(作为路径)
  3. A 排除 B --在所示示例中
  4. B排除A
  5. A 联盟 B
  6. A 与 B 相交

...以及一些与任何有用的东西都不匹配的更时髦的。

一些资源...

W3C site for elliptical curve commands

Good explanation for arc flags

Large-arc-flag:值为 0 表示使用较小的弧,而值为 1 表示使用较大的弧。

Sweep-flag:sweep-flag 决定是使用圆弧 (0) 还是它围绕轴 (1) 的反射。

关于javascript - venn.js 选择 Set[A] 除了 Set[B],我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37287986/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com