Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

drawing centered arcs in raphael js

I need to draw concentric arcs of various sizes using raphael.js. I tried to understand the code behind http://raphaeljs.com/polar-clock.html, which is very similar to what I want, but, whithout comments, it is quite difficult to fathom.

Ideally, I would need a function that creates a path that is at a given distance from some center point, starts at some angle and ends at some other angle.

like image 226
user592699 Avatar asked Sep 10 '25 05:09

user592699


2 Answers

That answer is ok, but cant be animated. I ripped the important stuff out of polar-clock for you. Here is a red arc that animates growing. enjoy.

// Custom Arc Attribute, position x&y, value portion of total, total value, Radius
var archtype = Raphael("canvas", 200, 100);
archtype.customAttributes.arc = function (xloc, yloc, value, total, R) {
    var alpha = 360 / total * value,
        a = (90 - alpha) * Math.PI / 180,
        x = xloc + R * Math.cos(a),
        y = yloc - R * Math.sin(a),
        path;
    if (total == value) {
        path = [
            ["M", xloc, yloc - R],
            ["A", R, R, 0, 1, 1, xloc - 0.01, yloc - R]
        ];
    } else {
        path = [
            ["M", xloc, yloc - R],
            ["A", R, R, 0, +(alpha > 180), 1, x, y]
        ];
    }
    return {
        path: path
    };
};

//make an arc at 50,50 with a radius of 30 that grows from 0 to 40 of 100 with a bounce
var my_arc = archtype.path().attr({
    "stroke": "#f00",
    "stroke-width": 14,
    arc: [50, 50, 0, 100, 30]
});

my_arc.animate({
    arc: [50, 50, 40, 100, 30]
}, 1500, "bounce");
like image 124
genkilabs Avatar answered Sep 13 '25 12:09

genkilabs


Here's how I have done it. The following code allows you to specify a start and end angle as well as an inner and outer radius (useful for doing those trendy donut style pie charts). The solution doesn't rely on approximating a curve with line segments and can be animated as per the clock example mentioned in the original question.

First create your Raphael drawing area; the following assumes a div with id "raphael_paper" in your HTML file:

var paper = Raphael("raphael_paper", 800, 800);

to this Raphael object we add a custom arc attribute, a function which takes the center of a circle (x and y coords), a start angle, an end angle, an inner radius and an outer radius:

paper.customAttributes.arc = function (centerX, centerY, startAngle, endAngle, innerR, outerR) {
    var radians = Math.PI / 180,
        largeArc = +(endAngle - startAngle > 180);
        // calculate the start and end points for both inner and outer edges of the arc segment
        // the -90s are about starting the angle measurement from the top get rid of these if this doesn't suit your needs
        outerX1 = centerX + outerR * Math.cos((startAngle-90) * radians),
        outerY1 = centerY + outerR * Math.sin((startAngle-90) * radians),
        outerX2 = centerX + outerR * Math.cos((endAngle-90) * radians),
        outerY2 = centerY + outerR * Math.sin((endAngle-90) * radians),
        innerX1 = centerX + innerR * Math.cos((endAngle-90) * radians),
        innerY1 = centerY + innerR * Math.sin((endAngle-90) * radians),
        innerX2 = centerX + innerR * Math.cos((startAngle-90) * radians),
        innerY2 = centerY + innerR * Math.sin((startAngle-90) * radians);

    // build the path array
    var path = [
        ["M", outerX1, outerY1], //move to the start point
        ["A", outerR, outerR, 0, largeArc, 1, outerX2, outerY2], //draw the outer edge of the arc
        ["L", innerX1, innerY1], //draw a line inwards to the start of the inner edge of the arc
        ["A", innerR, innerR, 0, largeArc, 0, innerX2, innerY2], //draw the inner arc
        ["z"] //close the path
    ];                   
    return {path: path};
};

now we can use this to draw arcs of a specified thickness, starting and ending wherever we want them to eg.

var redParams = {stroke: "#f00", "stroke-width": 1, fill:"#eee"},
    greenParams = {stroke: "#0f0", "stroke-width": 1, fill:"#eee"},
    blueParams = {stroke: "#00f", "stroke-width": 1, fill:"#eee"},
    cx = 300, cy = 300, innerRadius = 100, outerRadius = 250,

var red = paper.path().attr(redParams).attr({arc: [cx, cy, 0, 90, innerRadius, outerRadius]}); 
var green = paper.path().attr(greenParams).attr({arc: [cx, cy, 270, 320, innerRadius, outerRadius]}); 
var blue = paper.path().attr(blueParams).attr({arc: [cx, cy, 95, 220, innerRadius, outerRadius]});

This should result in three grey arc segments with red, blue and green 1px borders.

like image 35
Tom P Avatar answered Sep 13 '25 14:09

Tom P