使用javascript在SVG路径上跟随HTML元素

时间:2014-06-13 16:38:10

标签: javascript html svg

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

我创建了一个codepen来演示我到目前为止所拥有的内容: http://codepen.io/mikes000/pen/GIJab

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

有没有办法让它们沿着直线行进时保持相同的距离?

谢谢!

更新**

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

红色方块的位置是通过将它们前后移动黑盒宽度的一半来设置的。如果更改视框宽高比,沿着线移动时,线上每个点之间的距离会根据此值增加或减少。

我尝试使用容器div大小的精确视图框创建一个类似的SVG,红点正好位于黑盒子的两端。这并没有解决问题,因为我希望SVG的线可以扩展到它放在里面的任何大小的容器。

我认为如果有办法计算黑匣子的大小相对于它覆盖的线下多少像素的数量,红点就会准确排列。

任何想法如何实现这个或任何想法以更好的方式来解决这个问题?

1 个答案:

答案 0 :(得分:4)

查看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