我必须实现圆形逼近的想法,该逼近是具有N个角的规则多边形,而N由用户定义。
例如,如果N = 3,我将有一个三角形。在n = 5的情况下,我将开始一个类似于圆形的形状。随着N的增加,我将越来越接近圆形。
这个想法与以下问题/解决方案中的询问和回答非常相似: Draw regular polygons inscribed in a circle,但是他们使用raphael.js而不是D3.js。
我试图做的事情
var vis = d3.select("body").append("svg")
.attr("width", 1000)
.attr("height", 667);
var svg = d3.select('svg');
var originX = 200;
var originY = 200;
var outerCircleRadius = 60;
var outerCircle = svg.append("circle").attr({
cx: originX,
cy: originY,
r: outerCircleRadius,
fill: "none",
stroke: "black"
});
var chairWidth = 10;
var chairOriginX = originX + ((outerCircleRadius) * Math.sin(0));
var chairOriginY = originY - ((outerCircleRadius) * Math.cos(0));
var chair = svg.append("rect").attr({
x: chairOriginX - (chairWidth / 2),
y: chairOriginY - (chairWidth / 2),
width: chairWidth,
opacity: 1,
height: 20,
fill: "none",
stroke: "blue"
});
var n_number = 5
var n_angles = 360/n_number
var angle_start=0;
var angle_next;
console.log(chair.node().getBBox().x);
console.log(chair.node().getBBox().y);
chair.attr("transform", "rotate(" + (angle_start+n_angles+n_angles) + ", 200, 200)");
var circle = svg.append("circle")
.attr("cx", 195)
.attr("cy", 135)
.attr("r", 50)
.attr("fill", "red");
var chairOriginX2 = originX + ((outerCircleRadius) * Math.sin(0));
var chairOriginY2 = originY - ((outerCircleRadius) * Math.cos(0));
var chair2 = svg.append("rect").attr({
x: chairOriginX2 - (chairWidth / 2),
y: chairOriginY2 - (chairWidth / 2),
width: chairWidth,
opacity: 1,
height: 20,
fill: "none",
stroke: "blue"
});
console.log(chair2.node().getBBox().x);
console.log(chair2.node().getBBox().y);
我的想法没有用,我试图创建一个圆(“ outerCircle”),我将在基于N的圆的圆周(“ chair.attr(” transform“ ...”)中滑动,获得几个不同的(x,y)坐标。 然后,我将(x,y)坐标输入到多边形。
我认为我针对此问题的方法是错误的。另外,我卡住的部分是我无法顺着圆周移动并存储每个不同的(x,y)坐标。我尝试了“ console.log(chair2.node()。getBBox()。x);”但是它总是存储相同的坐标,它是原点。
答案 0 :(得分:2)
为了清楚起见,我简化了您的代码。要获取圆上某点的x,请使用Math.cos(angle)
,对于y,请使用Math.sin(angle)
。这是你的错误。现在,您可以更改n_number
var SVG_NS = 'http://www.w3.org/2000/svg';
var originX = 200;
var originY = 200;
var outerCircleRadius = 60;
var polygon = document.createElementNS(SVG_NS, 'polygon');
svg.appendChild(polygon);
let points="";
var n_number = 5;
var n_angles = 2*Math.PI/n_number
// building the value of the `points` attribute for the polygon
for(let i = 0; i < n_number; i++){
let x = originX + outerCircleRadius * Math.cos(i*n_angles);
let y = originY + outerCircleRadius * Math.sin(i*n_angles);
points += ` ${x},${y} `;
}
// setting the value of the points attribute of the polygon
polygon.setAttributeNS(null,"points",points)
svg{border:1px solid;width:90vh;}
polygon{fill: none;
stroke: blue}
<svg id="svg" viewBox = "100 100 200 200" >
<circle cx="200" cy="200" r="60" fill="none" stroke="black" />
</svg>
这是另一个演示,我在其中使用输入类型范围来更改n_number
变量
var SVG_NS = 'http://www.w3.org/2000/svg';
var originX = 200;
var originY = 200;
var outerCircleRadius = 60;
var polygon = document.createElementNS(SVG_NS, 'polygon');
svg.appendChild(polygon);
let points="";
var n_number = 5;
setPoints(n_number);
theRange.addEventListener("input", ()=>{
n_number = theRange.value;
setPoints(n_number)
});
function setPoints(n_number){
var n_angles = 2*Math.PI/n_number;
points = ""
// building the value of the `points` attribute for the polygon
for(let i = 0; i < n_number; i++){
let x = originX + outerCircleRadius * Math.cos(i*n_angles);
let y = originY + outerCircleRadius * Math.sin(i*n_angles);
points += ` ${x},${y} `;
}
// setting the value of the points attribute of the polygon
polygon.setAttributeNS(null,"points",points);
}
svg{border:1px solid; width:90vh;}
polygon{fill: none;
stroke: blue}
<p><input type="range" min="3" max="50" value="5" id="theRange" /></p>
<svg id="svg" viewBox = "100 100 200 200" >
<circle cx="200" cy="200" r="60" fill="none" stroke="black" />
</svg>
答案 1 :(得分:1)
answer提供的enxaneta非常好,并且无疑是经典的方法。但是,我经常喜欢让浏览器执行三角函数,而不是独自执行。典型示例包括我的answer至"Complex circle diagram"或one至"SVG marker - can I set length and angle?"。我什至不确定它们是否胜过更经典的,但尽管如此,我还是喜欢它们的简单性。
我的解决方案集中在SVGGeometryElement
及其方法.getTotalLength()
和.getPointAtLength()
上。由于SVGCircleElement
接口扩展了该接口,因此这些方法可用于具有以下含义的SVG圈:
.getTotalLength()
:圆的圆周。
.getPointAtLength()
:圆上x- / y坐标上给定长度的点。 definition的测量从3点钟位置开始,然后顺时针进行。
基于这些解释,很明显,您可以将圆的总长度(即圆的周长)除以近似点的数量。这使您可以沿圆弧到下一个点的步距。通过汇总这些距离,您可以使用第二种方法来获取每个点的x / y坐标。
可以按照以下几行进行编码:
// Calculate step length as circumference / number of points.
const step = circleElement.getTotalLength() / count;
// Build an array of points on the circle.
const data = Array.from({length: count}, (_, i) => {
const point = circleElement.getPointAtLength(i * step); // Get coordinates of next point.
return `${point.x},${point.y}`;
});
polygon.attr("points", data.join(" "));
光滑轻松!不涉及三角函数。
最后,一个完整的工作演示:
// Just setup, not related to problem.
const svg = d3.select("body")
.append("svg")
.attr("width", 500)
.attr("height", 500);
const circle = svg.append("circle")
.attr("cx", "150")
.attr("cy", "150")
.attr("r", "100")
.attr("fill", "none")
.attr("stroke", "black");
const polygon = svg.append("polygon")
.attr("fill", "none")
.attr("stroke", "blue");
const circleElement = circle.node();
const ranger = d3.select("#ranger").on("input", update);
const label = d3.select("label");
// This function contains all the relevant logic.
function update() {
let count = ranger.node().value;
label.text(count);
// Calculate step length as circumference / number of points.
const step = circleElement.getTotalLength() / count;
// Build an array of all points on the circle.
const data = Array.from({length: count}, (_, i) => {
const point = circleElement.getPointAtLength(i * step); // Get coordinates of next point.
return `${point.x},${point.y}`;
});
polygon.attr("points", data.join(" "));
}
update();
<script src="https://d3js.org/d3.v5.js"></script>
<p>
<input id="ranger" type="range" min="3" max="15" value="5">
<label for="ranger"></label>
</p>