【问题标题】:HTML elements following each other along SVG path with javascript使用 javascript 沿 SVG 路径相互跟随的 HTML 元素
【发布时间】:2014-08-04 07:04:27
【问题描述】:

我正在尝试让一些 html 元素沿着 SVG 路径相互跟随。我希望他们在沿着小路行驶时保持相同的距离。我还希望 SVG 图像可以缩放到容纳它的容器。

我创建了一个代码笔来演示我目前所拥有的: http://codepen.io/mikes000/pen/GIJab

我遇到的问题是,当元素沿 X 轴移动时,它们之间的距离似乎比在 Y 轴上的距离更远。

有没有办法让他们在沿线行驶时保持相同的距离?

谢谢!

更新**

经过进一步的摆弄后,我发现距离变化似乎是由于 SVG 视图框的纵横比增加,X 大于 Y。当它沿 X 轴向下拉伸 1px 时,可能在屏幕上变成 3px。

红色方块的位置是通过将它们前后移动黑框宽度的一半来设置的。沿线行驶时,如果更改了 viewbox 纵横比,则线上各点之间的距离会据此增加或减少。

我尝试创建一个类似的 SVG,其视图框与容器 div 的大小完全相同,并且红点一直位于黑框的末端。这并不能解决问题,因为我希望带有线条的 SVG 可以缩放到放置在其中的任何大小的容器。

我认为,如果有一种方法可以计算出黑盒大小的像素数与它覆盖红点的直线上的像素数之间的关系,那么红点就会完全对齐。

任何想法如何完成这个或任何想法更好地解决这个问题?

【问题讨论】:

  • 为什么不直接使用 SVG 元素呢?你所拥有的有什么问题(即预期的行为)?
  • 预期的行为是让红点正好位于正方形的前面和后面,但它们在沿 x 轴移动时会变得更远。我计划将来用图像或其他类型的内容替换方块。
  • 为了实现您的建议,您应该保持速度一致,并在沿路径移动时计算 x 和 y。但是,当前算法仅保持 delta_x 一致。当斜率较小时,这会使对象彼此分离。

标签: javascript html svg


【解决方案1】:

看看http://jsfiddle.net/4LzK4/

var svg = d3.select("#line").append("svg:svg").attr("width", "100%").attr("height", "100%");
var data = d3.range(50).map(function(){return Math.random()*10})
var x = d3.scale.linear().domain([0, 10]).range([0, 700]);
var y = d3.scale.linear().domain([0, 10]).range([10, 290]);
var line = d3.svg.line()
  .interpolate("cardinal")
  .x(function(d,i) {return x(i);})
  .y(function(d) {return y(d);})

var path = svg.append("svg:path").attr("d", line(data));
var circle = 
    svg.append("circle")
      .attr("cx", 100)
      .attr("cy", 350)
      .attr("r", 3)
      .attr("fill", "red");

var circleBehind = 
    svg.append("circle")
      .attr("cx", 50)
      .attr("cy", 300)
      .attr("r", 3)
      .attr("fill", "blue");

var circleAhead = 
    svg.append("circle")
      .attr("cx", 125)
      .attr("cy", 375)
      .attr("r", 3)
      .attr("fill", "green");

var pathEl = path.node();
var pathLength = pathEl.getTotalLength();
var BBox = pathEl.getBBox();
var scale = pathLength/BBox.width;
var offsetLeft = document.getElementById("line").offsetLeft;
var randomizeButton = d3.select("button");

svg.on("mousemove", function() {
  var x = d3.event.pageX - offsetLeft; 
  var beginning = x, end = pathLength, target;
  while (true) {
    target = Math.floor((beginning + end) / 2);
    pos = pathEl.getPointAtLength(target);
    if ((target === end || target === beginning) && pos.x !== x) {
        break;
    }
    if (pos.x > x)      end = target;
    else if (pos.x < x) beginning = target;
    else                break; //position found
  }
  circle
    .attr("opacity", 1)
    .attr("cx", x)
    .attr("cy", pos.y);

  posBehind = pathEl.getPointAtLength(target-10); 
  circleBehind
    .attr("opacity", 1)
    .attr("cx", posBehind.x)
    .attr("cy", posBehind.y);

  posAhead = pathEl.getPointAtLength(target+10); 
  circleAhead
    .attr("opacity", 1)
    .attr("cx", posAhead.x)
    .attr("cy", posAhead.y);

});

randomizeButton.on("click", function(){
  data = d3.range(50).map(function(){return Math.random()*10});
  circle.attr("opacity", 0)                                     
  path
    .transition()
    .duration(300)
    .attr("d", line(data));
});

不要自己计算前后圆圈的位置,而是使用 getPointAtLength 相对于必须保持在中间的对象的中心。

灵感来自:http://bl.ocks.org/duopixel/3824661

【讨论】:

  • 我正在使用您在示例中描述的 getPointAtLength 方法。问题是当将点向下移动 10px 时,由于 SVG 视图框的纵横比被拉伸,10px 在实际屏幕上变得超过 10px。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-02-26
  • 2020-04-07
  • 2018-06-02
  • 2021-09-09
  • 1970-01-01
  • 2021-12-15
  • 1970-01-01
相关资源
最近更新 更多