拉斐尔js。沿曲线填充颜色

时间:2013-05-04 08:19:44

标签: javascript raphael

我创建了一个圆圈,我可以在圆圈周围选择两个点。

我想填补这两点之间的部分。

Demo

如果您看到演示,我想填补两点之间的角度。

JS:

(function (Raphael) {
    Raphael.colorwheel = function (x, y, size, initcolor, element) {
        return new ColorWheel(x, y, size, initcolor, element);
    };
    var pi = Math.PI,
        doc = document,
        win = window,
        ColorWheel = function (x, y, size, initcolor, element) {
            size = size || 200;
            var w3 = 3 * size / 200,
                w1 = size / 200,
                fi = 1.6180339887,
                segments = 3,//pi * size / 50,
                size20 = size / 20,
                size2 = size / 2,
                padding = 2 * size / 200,
                t = this;

            var H = 1, S = 1, B = 1, s = size - (size20 * 4);
            var r = element ? Raphael(element, size, size) : Raphael(x, y, size, size),
                xy = s / 6 + size20 * 2 + padding,
                wh = s * 2 / 3 - padding * 2;
            w1 < 1 && (w1 = 1);
            w3 < 1 && (w3 = 1);



            // ring drawing
            var a = pi / 2 - pi * 2 / segments * 1.3,
                R = size2 - padding,
                R2 = size2 - padding - size20 * 2,
                path = ["M", size2, padding, "A", R, R, 0, 0, 1, R * Math.cos(a) + R + padding, R - R * Math.sin(a) + padding, "L", R2 * Math.cos(a) + R + padding, R - R2 * Math.sin(a) + padding, "A", R2, R2, 0, 0, 0, size2, padding + size20 * 2, "z"].join();

            for (var i = 0; i < segments; i++) {
                r.path(path).attr({
                    stroke: "none",
                    fill: "#8fd117",
                    transform: "r" + [(360 / segments) * i, size2, size2]
                });
            }

            r.path(["M", size2, padding, "A", R, R, 0, 1, 1, size2 - 1, padding, "l1,0", "M", size2, padding + size20 * 2, "A", R2, R2, 0, 1, 1, size2 - 1, padding + size20 * 2, "l1,0"]).attr({
                "stroke-width": w3,
                stroke: "#fff"
            });

            t.startCursor = r.set();
            var h = size20 * 2 + 2;
            t.startCursor.push(r.rect(size2 - h / fi / 2, padding - 1, h / fi, h, 3 * size / 200).attr({
                stroke: "#00A0C6",
                opacity: .5,
                "stroke-width": w3
            }));
            t.startCursor.push(t.startCursor[0].clone().attr({
                stroke: "#00A0C6",
                opacity: 1,
                "stroke-width": w1
            }));


            t.endCursor = r.set();
            var h = size20 * 2 + 2;
            t.endCursor.push(r.rect(size2 - h / fi / 2, padding - 1, h / fi, h, 3 * size / 200).attr({
                stroke: "#F96E5B",
                opacity: .5,
                "stroke-width": w3
            }));

            t.endCursor.push(t.endCursor[0].clone().attr({
                stroke: "#F96E5B",
                opacity: 1,
                "stroke-width": w1
            }));



            t.ring = r.path(["M", size2, padding, "A", R, R, 0, 1, 1, size2 - 1, padding, "l1,0M", size2, padding + size20 * 2, "A", R2, R2, 0, 1, 1, size2 - 1, padding + size20 * 2, "l1,0"]).attr({
                fill: "#000",
                opacity: 0,
                stroke: "none"
            }); 

            t.H = t.S = t.B = 1;
            t.raphael = r;
            t.size2 = size2;
            t.wh = wh;
            t.x = x;
            t.xy = xy;
            t.y = y;


            t.endCursor.attr({transform: "r" + [50, t.size2, t.size2]});

            // events
            t.ring.drag(function (dx, dy, x, y) {
                t.docOnMove(dx, dy, x, y);
            }, function (x, y) { 
                // Rotate on click 
                t.setH(x - t.x - t.size2, y - t.y - t.size2);
            }, function () { 
            }); 
        },
        proto = ColorWheel.prototype;

    proto.setH = function (x, y) { 

        var d = Raphael.angle(x, y, 0, 0); 

        this.H = (d + 90) / 360;
        var a  = 0;

        if(d > 270) {
            d = d - 270;
        }
        else {
            d = d + 90;
        } 

        var m = Math.abs(d - this.startCursor[0]._.deg);
        var n = Math.abs(d - this.endCursor[0]._.deg);

        if(m > 180) {
            m = 360 - m ;
        }
        if(n > 180) {
            n = 360 - n;
        }    

        if( m <= n) {
            this.startCursor.attr({transform: "r" + [d, this.size2, this.size2]});
        }
        else {
            this.endCursor.attr({transform: "r" + [d, this.size2, this.size2]});
        }

        m = this.startCursor[0]._.deg ;
        n = this.endCursor[0]._.deg;

        if(m > 360) {
            m = m - 360;
        }
        if( n > 360 ) {
            n = n - 360;
        } 

        var diff = m > n ? m - n : n - m;

        this.onchange(m,n,diff);
    };

    proto.docOnMove = function (dx, dy, x, y) {
        this.setH(x - this.x - this.size2, y - this.y - this.size2);

    };

})(window.Raphael);



window.onload = function () {
    var cp2 = Raphael.colorwheel(60, 20, 200, "#eee");
    var X = document.getElementById('x');
    var Y = document.getElementById('y');
    var angle = document.getElementById('angle');

    cp2.onchange = function (x, y, ang) {
        X.innerHTML = Math.round(x * 100) / 100;
        Y.innerHTML = Math.round(y * 100) / 100;
        angle.innerHTML = Math.round(ang * 100) / 100;
    }
};

HTML:

<div id="wrapper">X : <span id="x">0</span>
    <br>Y: <span id="y">50</span> 
    <br>Angle: <span id="angle">50</span> 
</div>

CSS:

  body {
      background: #e6e6e6;
  }
  #wrapper {
      position: absolute;
      top: 240px;
      left: 100px;
  }

更新

在Chris的帮助下,

我取得了一些成功。

Demo

错误:
 如果你先开绿色,红色休息,
 2.如果先开始红色并使角度大于180度,当绿色降低到180度以下时,它会再次破裂。

更新2
DEMO
错误:
 1.如果先开始红色并使角度大于180度,当绿色降低到180度以下时,它会再次破裂  2.有时反方向的弧线。

2 个答案:

答案 0 :(得分:4)

酷项目。您只需要在色轮上添加一个椭圆弧,然后在onchange事件上重绘路径。

我把你带到了这里的一半:如果移动橙色光标,它会起作用,如果移动蓝色光标​​则完全断开。

开始:

        t.x0 = t.startCursor[0].attr("x") + t.startCursor[0].attr("width") / 2;
        t.y0 = t.startCursor[0].attr("y") + t.startCursor[0].attr("height") / 2;
        t.R1 = (R2 + R) / 2;
        t.x1 = t.x0 + t.R1 * Math.sin(50 * Math.PI / 180);
        t.y1 = t.y0 + t.R1 - t.R1 * Math.cos(50 * Math.PI / 180);

        t.arc = r.path("M" + t.x0 + "," + t.y0 + "A" + t.R1 + "," + t.R1 + " 50 0,1 " + t.x1 + "," + t.y1)
        .attr({
            stroke: "#009900",
            "stroke-width": 10
        });

更新时间:

    if (n > 180) {
        flag = 1;
    }

    var diff = m > n ? m - n : n - m;

    t.x0 = t.x0 + t.R1 * Math.sin(m * Math.PI / 180);
    t.y0 = t.y0 + t.R1 - t.R1 * Math.cos(m * Math.PI / 180);
    t.x1 = t.x0 + t.R1 * Math.sin(diff * Math.PI / 180);
    t.y1 = t.y0 + t.R1 - t.R1 * Math.cos(diff * Math.PI / 180);

    t.arc = t.arc.attr("path", "M" + t.x0 + "," + t.y0 + "A" + t.R1 + "," + t.R1 + " " +  diff + " " +  flag + ",1 " + t.x1 + "," + t.y1);

jsfiddle

应该可以从这里拿走它。

5月8日更新:

您可以通过更改差异上的标记而不是第二个角度来修复您的第一个问题:

    if (diff > 180) { 
        flag = 1;
    }

触发第二个问题的事件是第二个角度(红色手柄)通过0度标记。捕获这个的最简单方法就是将角度加上360,如果它小于第一个角度:

    var m = this.startCursor[0]._.deg ;
    var n = this.endCursor[0]._.deg;
    var t = this;        
    var flag = 0;
    var sweep = 1; 

    var path = "";
    if (n < m) {
       m += 360;
    } 

    var diff = Math.abs(m - n); 

    if (diff > 180) { 
        flag = 1;
    }

Here's the fiddle

注意:您正在捕捉(n > 360)(m > 360)的情况,但这似乎没有必要 - 角度到达此处已设置在360以下的代码中,至少在Chrome中。

答案 1 :(得分:4)

这是有效的解决方案:

<强> Demo

(function (Raphael) {
    Raphael.colorwheel = function (x, y, size, initcolor, element) {
        return new ColorWheel(x, y, size, initcolor, element);
    };
    var pi = Math.PI,
        doc = document,
        win = window,
        ColorWheel = function (x, y, size, initcolor, element) {
            size = size || 200;
            var w3 = 3 * size / 200,
                w1 = size / 200,
                fi = 1.6180339887,
                segments = 3,//pi * size / 50,
                size20 = size / 20,
                size2 = size / 2,
                padding = 2 * size / 200,
                t = this;

            var H = 1, S = 1, B = 1, s = size - (size20 * 4);
            var r = element ? Raphael(element, size, size) : Raphael(x, y, size, size),
                xy = s / 6 + size20 * 2 + padding,
                wh = s * 2 / 3 - padding * 2;
            w1 < 1 && (w1 = 1);
            w3 < 1 && (w3 = 1);

            // ring drawing
            var a = pi / 2 - pi * 2 / segments * 1.3,
                R = size2 - padding,
                R2 = size2 - padding - size20 * 2,
                path = ["M", size2, padding, "A", R, R, 0, 0, 1, R * Math.cos(a) + R + padding, R - R * Math.sin(a) + padding, "L", R2 * Math.cos(a) + R + padding, R - R2 * Math.sin(a) + padding, "A", R2, R2, 0, 0, 0, size2, padding + size20 * 2, "z"].join();
            for (var i = 0; i < segments; i++) {
                r.path(path).attr({
                    stroke: "none",
                    fill: "#8fd117",
                    transform: "r" + [(360 / segments) * i, size2, size2]
                });
            }

            r.path(["M", size2, padding, "A", R, R, 0, 1, 1, size2 - 1, padding, "l1,0", "M", size2, padding + size20 * 2, "A", R2, R2, 0, 1, 1, size2 - 1, padding + size20 * 2, "l1,0"]).attr({
                "stroke-width": w3,
                stroke: "#fff"
            });


            t.startCursor = r.set();
            var h = size20 * 2 + 2;

            t.startCursor.push(r.rect(size2 - h / fi / 2, padding - 1, h / fi, h, 3 * size / 200).attr({
                stroke: "#00A0C6",
                opacity: 1,
                "stroke-width": w3
            }));
            t.startCursor.push(t.startCursor[0].clone().attr({
                stroke: "#00A0C6",
                fill : "#8fd117", 
                opacity: 1,
                "stroke-width": w1
            }));

            t.endCursor = r.set();
            var h = size20 * 2 + 2;

            t.endCursor.push(r.rect(size2 - h / fi / 2, padding - 1, h / fi, h, 3 * size / 200).attr({
                stroke: "#F96E5B",
                opacity: 1,
                "stroke-width": w3,

            }));

            t.endCursor.push(t.endCursor[0].clone().attr({
                stroke: "#F96E5B",
                fill : "#8fd117",
                opacity: 1,
                "stroke-width": w1
            }));

            t.ring = r.path(["M", size2, padding, "A", R, R, 0, 1, 1, size2 - 1, padding, "l1,0M", size2, padding + size20 * 2, "A", R2, R2, 0, 1, 1, size2 - 1, padding + size20 * 2, "l1,0"]).attr({
                fill: "#000",
                opacity: 0,
                stroke: "none"
            }); 

            t.H = t.S = t.B = 1;
            t.raphael = r;
            t.size2 = size2;
            t.wh = wh;
            t.x = x;
            t.xy = xy;
            t.y = y;

            t.endCursor.attr({transform: "r" + [50, t.size2, t.size2]});

            t.x0 = t.startCursor[0].attr("x") + t.startCursor[0].attr("width") / 2;
            t.y0 = t.startCursor[0].attr("y") + t.startCursor[0].attr("height") / 2;
            t.initX0 = t.x0;
            t.initY0 = t.y0;
            t.R1 = (R2 + R) / 2;
            t.x1 = t.x0 + t.R1 * Math.sin(50 * Math.PI / 180);
            t.y1 = t.y0 + t.R1 - t.R1 * Math.cos(50 * Math.PI / 180);
            t.initX1 = t.x1;
            t.initY1 = t.y1;
            var path = "M" + t.x0 + "," + t.y0 + "A" + t.R1 + "," + t.R1 + " 50 0,1 " + t.x1 + "," + t.y1;

            t.arc = r.path(path)
            .attr({
                stroke: "#009900",
                "stroke-width": 10
            });


            t.startCursor.drag(function (dx, dy, x, y) {
                   t.docOnMove(dx, dy, x, y,'startCursor');
                }, function (x, y) { 
                    t.setH(x - t.x - t.size2, y - t.y - t.size2,'startCursor');
                }, function () { 

            }); 

            t.endCursor.drag(function (dx, dy, x, y) {
                   t.docOnMove(dx, dy, x, y,'endCursor');
                }, function (x, y) { 
                    t.setH(x - t.x - t.size2, y - t.y - t.size2,'endCursor');
                }, function () { 

            }); 

            t.startCursor.toFront();
            t.endCursor.toFront();
        },
        proto = ColorWheel.prototype;

    proto.setH = function (x, y,cursor) {  
        var d = Raphael.angle(x, y, 0, 0);
        if(d > 270) {
            d = d - 270;
        }
        else {
            d = d + 90;
        } 

        if((cursor === 'startCursor' && d > this.endCursor[0]._.deg) || (cursor === 'endCursor' && d <= this.startCursor[0]._.deg)) {
            return;
        }

        if(cursor === 'startCursor') {
            this.startCursor.attr({transform: "r" + [d, this.size2, this.size2]});
        }
        else {
            this.endCursor.attr({transform: "r" + [d, this.size2, this.size2]});
        }   

        var m = this.startCursor[0]._.deg ;
        var n = this.endCursor[0]._.deg;
        var t = this;        
        var flag = 0;

        if(m > 360) {
            m = m - 360;
            flag = 1;  
        }

        if( n > 360 ) {
            n = n - 360;
        } 


        var diff = Math.abs(m - n); 

        if (diff > 180) { 
            flag = 1;
        }

        var path = "";
        var sweep = 1; 

        if(cursor === 'endCursor') { 
            t.x1 = t.initX0 + t.R1 * Math.sin(n * Math.PI / 180);
            t.y1 = t.initY0 + t.R1 - t.R1 * Math.cos(n * Math.PI / 180);
        }
        else { 
            t.x0 = t.initX0 + t.R1 * Math.sin(m * Math.PI / 180);
            t.y0 = t.initY0 + t.R1 - t.R1 * Math.cos(m * Math.PI / 180);
        }

        console.log(m,t.x0,t.y0,t.x1,t.y1);

        path = "M" + t.x0 + "," + t.y0 + "A" + t.R1 + "," + t.R1 + " " +  diff + " " +  flag + "," + sweep + " " + t.x1 + "," + t.y1;

        t.arc = t.arc.attr("path", path );

        this.onchange(m,n,diff);
    };

    proto.docOnMove = function (dx, dy, x, y,cursor) {
        this.setH(x - this.x - this.size2, y - this.y - this.size2,cursor);

    };

})(window.Raphael);

window.onload = function () {
    var cp2 = Raphael.colorwheel(60, 20, 200, "#eee");
    var X = document.getElementById('x');
    var Y = document.getElementById('y');
    var angle = document.getElementById('angle');

    cp2.onchange = function (x, y, ang) {
        X.innerHTML = Math.round(x * 100) / 100;
        Y.innerHTML = Math.round(y * 100) / 100;
        angle.innerHTML = Math.round(ang * 100) / 100;


    }
};