【问题标题】:How to position svg circles on a line and curve it?如何将svg圆定位在一条线上并使其弯曲?
【发布时间】:2016-11-15 01:39:33
【问题描述】:

我正在制作像 seat.io 这样的软件,我正在尝试弯曲圆圈的线。我首先使用 d3.js 创建一个带有 svg 圆圈的正方形。

y 坐标

我首先找到了中间的圆,并将它的 cy 设置为 0,然后依次设置后续的圆(每行递增 12。然后我意识到,如果它是偶数,它就找不到中间点。

我决定使用 bhaskara 公式来查找曲线坐标,但我不知道如何在循环内定位它:

$("#curve").on("change",function(){
    var a = $(this).val();
    var q = quant_col2;

    console.log(q);
    console.log(quant_line2);

    var half = Math.round(quant_col2/2) - 1;

    console.log("media: " + half);

    var value = 0;

    var circles = svg.selectAll("circle").attr("cy", function(d, i){

        var cy = $(this).attr("cy");

        var resultado = baskara(quant_col2,quant_line2,0);

        var xv = -Math.abs(quant_line2)/(2 * quant_col2);

        var xy = -Math.abs(delta(quant_col2,quant_line2,0))/4 * quant_col2;


        if(i < q){
            if(i  == half) {
                return value;
            }
        }
        if(i == q - 1){
            half = half + quant_col2;
            q = q + quant_col2;
            value = value + 12;
            return cy;
        }

        return cy;
    });

    console.log($(this).val());
});

如何使它弯曲并正确定位圆圈? 感谢您的帮助。

编辑 1: 没有数据参数的代码

var curva = svg.selectAll("circle")
        .attr("cx", function(d,i) { 
            var cx = $(this).attr("cx");
            return p_parab.x(cx);
        })
        .attr("cy", function(d,i) { 
            var cy = $(this).attr("cy");    
            return p_parab.y(cy) + 15* cy;
        });

【问题讨论】:

  • 我已经阅读了您的问题 3 次,但不知道您在问什么。你能创建一些可运行的代码来说明你的问题吗?
  • 嗨@Mark,谢谢!我在这里创建了一个 Fiddle jsfiddle.net/jaquedeveloper/zvb4uL91 单击 Draw 和 Rows,您将能够看到它现在是如何工作的以及公式
  • @Mark,我一直在使用您提供的解决方案,对此我有疑问。你知道我怎样才能得到一个对称的结果。我需要第一个和最后一个圆圈处于同一水平(y 轴)。您评论中提供的解决方案是迄今为止最好的解决方案,我非常感谢您的帮助。这是我需要做的最后一件事。我一直在努力,但仍然无法获得这种对称性。这是唯一剩下的东西。
  • 嗨@Mark,我想了解这个等式,我可以调整它以完美运行 30 圈线。但是如果圈数小于它,例如,10,它就不能正常工作。我已经对数字进行了一些调整,但我想使其自动化,以便无论每行有多少个圆圈都能正常工作......我该怎么做?这是小提琴:jsfiddle.net/jaquedeveloper/fpzqf2xr 要调整圈数,请更改 quant_col2 变量。
  • @steve-ladavich 你能帮我解决这个问题吗?

标签: javascript math d3.js svg logic


【解决方案1】:

我绝对不确定我是否理解你的问题,但如果你想沿着曲线定位圆圈,我建议......

  1. 写出你想要的曲线方程
  2. 将该曲线转换为parametric equation
  3. 对 cx 使用 x 方程,对 cy 使用 y 方程

参数方程将为您提供单行。对于每个额外的行,您需要考虑该行中所有 cy 的额外偏移量。

这是一个非常粗略的示例,供您构建...

const p_circle = {
  x(t){ return 100*Math.cos((t+10)/10)+150 },
  y(t){ return 100*Math.sin((t+10)/10)-80 }
}

const p_parab = {
  x(t){ return -(10*t-5)+100 },
  y(t){ return -(t-5)*(t-5)+20 }
}



let t = Array.prototype.concat(
  Array.from(Array(10).keys()).map(d=>[d,1]), //row 1
  Array.from(Array(10).keys()).map(d=>[d,2]), //row 2
  Array.from(Array(10).keys()).map(d=>[d,3])  //row 3
)


const p_parab_2 = {
  x(t){ return (10*t-5)+100 }, // removing "-" so that first seat is on left, not right
  y(t){ return -(t-5)*(t-5)+20 }
}

// adding 11th seat to center around seat 5 (seat in the center)
let t2 = Array.prototype.concat(
  Array.from(Array(11).keys()).map(d=>[d,1]), //row 1
  Array.from(Array(11).keys()).map(d=>[d,2]), //row 2
  Array.from(Array(11).keys()).map(d=>[d,3])  //row 3
)

console.log(t)

d3.select("svg").selectAll(".circ")
  .data(t)
  .enter()
  .append("circle")
    .attr("class", "circ")
    .attr("r",5)
    .attr("fill","red")
    .attr("cx", (d) => p_circle.x(d[0]))
    .attr("cy", (d) => p_circle.y(d[0]) + 15*d[1])

d3.select("svg").selectAll(".parab2")
  .data(t2)
  .enter()
  .append("circle")
    .attr("class", "parab2")
    .attr("r",7)
    .attr("fill","blue")
    .attr("cx", (d) => p_parab.x(d[0]))
    .attr("cy", (d) => p_parab.y(d[0]) + 15*d[1])

d3.select("svg").selectAll(".parab")
  .data(t)
  .enter()
  .append("circle")
    .attr("class", "parab")
    .attr("r",5)
    .attr("fill","green")
    .attr("cx", (d) => p_parab.x(d[0]))
    .attr("cy", (d) => p_parab.y(d[0]) + 15*d[1])
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

<svg height="250" width="250"></svg>

【讨论】:

  • 是的,你已经理解了这个问题,这就是我需要的!但我看到这条曲线在左边,我希望最左边和最右边元素的 y 坐标是相同的......我怎样才能实现它?这与 cos 和 sin 值有关系吗?
  • 玩弄参数方程和“t”值,直到你看到你想要的样子。请记住,方程式正在绘制曲线,而 t 值表示您要沿着曲线绘制每个圆的位置。对于这条曲线,t=5 是中心座位,但我有座位 t=0 到 t=10(11 个座位)。因为我写方程的方式。第 0 个座位比第 10 个座位离中心 1 个座位,给人的印象是“待定”——我将添加一个编辑
  • 我刚刚调整了宽度并更改了曲线的参数,它就起作用了。我没有数字的 d 数据...我试图只将 cy 和 cx 值放入我的自动化代码中,但它没有按预期工作。我该如何调整它?我已经编辑了问题
  • @JaquelinePassos,“.data()”部分有点像在 D3 中隐藏了 for loop/array.prototype.map 调用。使用“.data().enter().append()”为每个座位绘制一个新圆圈。您可能希望基于 makeSeatArray(nRows = 5, nCols = 10){ return a 2d array } 等函数创建数据,然后使用一般更新模式 bl.ocks.org/mbostock/3808234 进行相应渲染
  • @JaquelinePassos 在您链接的 JS 小提琴中,您在第 111、112 行使用双循环 - D3 数据绑定基本上为您处理。我强烈建议您利用 D3 进行数据绑定,但如果您想手动执行此操作,则必须将这些 for 循环重新合并到此方法中(并“手动”绘制每个圆圈)
【解决方案2】:

我喜欢@steveladavich 的回答,但我会提出一个替代方案。您可以使用d3 的曲线拟合点的能力,然后将圆圈放置在生成的路径上:

var r = 10,
  points = [];
for (var i = 0; i < 10; i++) {
  points.push({
    x: (500 / 10) * i,
    y: Math.random() * 500
  });
}

var line = d3.line()
  .x(function(d) {
    return d.x;
  })
  .y(function(d) {
    return d.y;
  })
  .curve(d3.curveCardinal);

var svg = d3.select("body")
  .append("svg")
  .attr("width", 500)
  .attr("height", 500);

var path = svg.append("g")
  .datum(points)
  .append("path")
  .attr("d", line)
  .style("fill", "none")
  .style("stroke", "none")
  .node();

var pathLength = path.getTotalLength();
svg.append("g")
  .selectAll("circle")
  .data(d3.range(0, pathLength, r))
  .enter()
  .append("circle")
  .attr("transform", function(d) {
    var p = path.getPointAtLength(d);
    return "translate(" + p.x + "," + p.y + ")";
  })
  .attr("r", r / 2)
  .style("fill", "steelblue");
&lt;script src="http://d3js.org/d3.v4.js"&gt;&lt;/script&gt;

【讨论】:

  • 马克和@JaquelinePassos,我认为这是更好的答案。让 D3/SVG 完成创建曲线的工作比通过 x/y 方程自行管理更容易。 getPointAtLength() 的添加也是对创建 t 值数组的改进。对于这个应用程序,我认为将这种方法与像quadraticCurveTo() 这样的 d3 路径生成器(而不是 d3 的曲线拟合)一起使用会使这个答案更好。那时,修改控制点将成为一个易于编辑/可定制的解决方案
  • 实际上我不确定如何使用它来使其工作,因为我没有真正的线路。这些圆圈的排列方式就好像它们在同一条线上一样,并且我有 x 条线。我无法用这种方法得到想要的结果......我从想要的结果中得到的更接近的结果是:jsfiddle.net/jaquedeveloper/gcg2m3s2。我仍然在寻找如何在不同的层面上做到这一点。例如,类似的 x 和 y 值(以获得“几乎直线”的线......然后使其彼此保持距离......感谢任何帮助
  • @JaquelinePassos,仍然不完全确定您要做什么,但请参阅here 了解一种可能的实现方式。调整parabDepth 以获得更大的曲线。
  • @Mark 它可以用作座位排,就像电影院地图一样,其中我有代表座位的 svg 圆圈,并排在一个“线”中。我没有真正的线,当我说线时,这意味着圆圈具有相同的 y 值......每条线都是一行。我想指定曲线,用户将能够设置曲线规范来创建座椅的表示。到目前为止,您提供的答案非常适用!非常感谢!我会实施它并可能会接受它。
猜你喜欢
  • 2017-12-18
  • 2017-03-19
  • 1970-01-01
  • 2016-06-23
  • 1970-01-01
  • 2017-02-23
  • 1970-01-01
  • 2019-04-28
  • 2017-09-03
相关资源
最近更新 更多