【问题标题】:How to drag a shape along a given path如何沿给定路径拖动形状
【发布时间】:2014-08-11 18:52:29
【问题描述】:

我有一个简单的虚拟文件,我用它来做一些测试。预期的结果是沿着路径拖动红色圆圈。问题是我不知道如何关联这两种形状。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />    
    <script src="raphael-min.js"></script>    
</head>
<body>    
<script type="text/javascript">    
// Creates canvas 320 × 200 at 10, 50
var r = Raphael(10, 50, 320, 200);

var p = r.path("M100,100c0,50 100-50 100,0c0,50 -100-50 -100,0z").attr({stroke: "#ddd"}),
    e = r.ellipse(104, 100, 4, 4).attr({stroke: "none", fill: "#f00"}),


/*var c = r.circle(100, 100, 50).attr({
    fill: "hsb(.8, 1, 1)",
    stroke: "none",
    opacity: .5
});*/


var start = function () {
    // storing original coordinates
    this.ox = this.attr("cx");
    this.oy = this.attr("cy");
    this.attr({opacity: 1});
},
move = function (dx, dy) {
    // move will be called with dx and dy
    this.attr({cx: this.ox + dx, cy: this.oy + dy});
},
up = function () {
    // restoring state
    this.attr({opacity: 1});
};
e.drag(move, start, up);    
</script>
</body>
</html>

【问题讨论】:

  • 主要思想是获得类似于 animateAlong 但拖动而不是动画的东西。
  • 这是一个供人们使用的 jsFiddle:jsfiddle.net/8T9NQ
  • 一般情况下,需要将光标位置投影到路径上,找到路径上最近的点。很可能在最接近光标的路径上有两个(或更多,或无限)点,因此您需要消除歧义以选择最佳的。

标签: javascript graphics svg raphael


【解决方案1】:

您没有具体说明您希望交互如何进行,所以我使用了对我来说最自然的方式。

我们可以假设点必须保留在路径上,所以它的位置必须由下式给出

p.getPointAtLength(l);

对于一些l。要找到l,我们可以搜索曲线和光标位置之间距离的局部最小值。我们使用l0 初始化搜索,其中l0l 的值当前 定义了点的位置。

请参阅此处的 JSfiddle 以获取工作示例:

http://jsfiddle.net/fuzic/kKLtH/

代码如下:

var searchDl = 1;
var l = 0;

// Creates canvas 320 × 200 at 10, 50
var r = Raphael(10, 50, 320, 200);

var p = r.path("M100,100c0,50 100-50 100,0c0,50 -100-50 -100,0z").attr({stroke: "#ddd"}),
    pt = p.getPointAtLength(l);
    e = r.ellipse(pt.x, pt.y, 4, 4).attr({stroke: "none", fill: "#f00"}),
    totLen = p.getTotalLength(),


start = function () {
    // storing original coordinates
    this.ox = this.attr("cx");
    this.oy = this.attr("cy");
    this.attr({opacity: 1});
},
move = function (dx, dy) {
    var tmpPt = {
        x : this.ox + dx, 
        y : this.oy + dy
    };
    l = gradSearch(l, tmpPt);
    pt = p.getPointAtLength(l);
    this.attr({cx: pt.x, cy: pt.y});
},
up = function () {
    this.attr({opacity: 1});
},
gradSearch = function (l0, pt) {
    l0 = l0 + totLen;
    var l1 = l0,
        dist0 = dist(p.getPointAtLength(l0 % totLen), pt),
        dist1,
        searchDir;

    if (dist(p.getPointAtLength((l0 - searchDl) % totLen), pt) > 
       dist(p.getPointAtLength((l0 + searchDl) % totLen), pt)) {
        searchDir = searchDl;
    } else {
        searchDir = -searchDl;
    }

    l1 += searchDir;
    dist1 = dist(p.getPointAtLength(l1 % totLen), pt);
    while (dist1 < dist0) {
        dist0 = dist1;
        l1 += searchDir;
        dist1 = dist(p.getPointAtLength(l1 % totLen), pt);
    }
    l1 -= searchDir;

    return (l1 % totLen);
},
dist = function (pt1, pt2) {
    var dx = pt1.x - pt2.x;
    var dy = pt1.y - pt2.y;
    return Math.sqrt(dx * dx + dy * dy);
};
e.drag(move, start, up);​

【讨论】:

【解决方案2】:

一个圆形对象的中心有一个 x,y 坐标和一个半径。要确保圆保持在线上,只需找到圆心与直线本身的交点即可。

为此,您需要存储线路的起点和终点坐标。然后使用直线方程:y = mx + b,您可以找到斜率和 y 截距。一旦你有了直线的函数,你就可以通过插入不同的 x 值来为圆生成新的坐标。

此外,通过将圆的 x,y 坐标插入您的函数,您可以检查圆是否在线。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-05-12
    • 2015-01-20
    • 1970-01-01
    • 1970-01-01
    • 2014-07-09
    • 2016-03-11
    • 1970-01-01
    • 2014-08-13
    相关资源
    最近更新 更多