2011-02-21 3 views
25

Мне нужно нарисовать концентрические дуги разных размеров, используя raphael.js. Я попытался понять код за http://raphaeljs.com/polar-clock.html, который очень похож на то, что я хочу, но, без комментариев, его довольно сложно понять.рисунок центрированных дуг в raphael js

В идеале мне нужна функция, которая создает путь, который находится на заданном расстоянии от некоторой центральной точки, начинается под некоторым углом и заканчивается под другим углом.

ответ

53

Этот ответ хорошо, но не могу быть анимированы. Я разорвал важные вещи из полярных часов для вас. Вот красная дуга, которая оживляет рост. наслаждаться.

// 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"); 
+9

Для удобства, вот этот ответ как jsfiddle, где вы можете указать, сколько кругов нужно рисовать: http://jsfiddle.net/Bzdnm/2/ – user568458

+0

Как и в случае с этим и примером Polar Clock, кто-нибудь знает, как изменить это, чтобы начальная точка не всегда была в 12 часов? Я догадался, что стартовая ценность из 100 будет делать это, но она, похоже, не работает. – daxiang28

+0

Используйте метод поворота. CODE {my_arc.rotate (-90, 50, 50) .animate ({ arc: [50, 50, количество, 100, 30] }, 1500, «bounce»); } Вы можете найти больше на нем в документах Рафаэля. – genkilabs

7

Собственно нашел ответ сам. Сначала я подумал о чем-то, что связано с кривыми Безье, но это просто работает.

-> создает путь с использованием синтаксиса SVG пути, который работает как с Рафаэлем

function arc(center, radius, startAngle, endAngle) { 
    angle = startAngle; 
    coords = toCoords(center, radius, angle); 
    path = "M " + coords[0] + " " + coords[1]; 
    while(angle<=endAngle) { 
     coords = toCoords(center, radius, angle); 
     path += " L " + coords[0] + " " + coords[1]; 
     angle += 1; 
    } 
    return path; 
} 

function toCoords(center, radius, angle) { 
    var radians = (angle/180) * Math.PI; 
    var x = center[0] + Math.cos(radians) * radius; 
    var y = center[1] + Math.sin(radians) * radius; 
    return [x, y]; 
} 
+0

Я думал, что сделаю [версию php] (http://ideone.com/m4fMU) в случае, если кто-то заинтересован. –

+0

Не нужно приближать круг самостоятельно. SVG уже предлагает эллиптические пути – Cuadue

7

Просто удалить некоторые догадки из ответа user592699, это полный код, который работает:

<script src="raphael.js"></script> 
<script> 

    var paper = Raphael(20, 20, 320, 320); 

    function arc(center, radius, startAngle, endAngle) { 
     angle = startAngle; 
     coords = toCoords(center, radius, angle); 
     path = "M " + coords[0] + " " + coords[1]; 
     while(angle<=endAngle) { 
      coords = toCoords(center, radius, angle); 
      path += " L " + coords[0] + " " + coords[1]; 
      angle += 1; 
     } 
     return path; 
    } 

    function toCoords(center, radius, angle) { 
     var radians = (angle/180) * Math.PI; 
     var x = center[0] + Math.cos(radians) * radius; 
     var y = center[1] + Math.sin(radians) * radius; 
     return [x, y]; 
    } 

    paper.path(arc([100, 100], 80, 0, 270)); // draw an arc 
              // centered at (100, 100), 
              // radius 80, starting at degree 0, 
              // beginning at coordinate (80, 0) 
              // which is relative to the center 
              // of the circle, 
              // going clockwise, until 270 degree 

</script> 
+1

http://jsfiddle.net/pajtai/9LKEu/ –

+0

Спасибо за очистку! – plang

10

Вот как я это сделал. Следующий код позволяет указать начальный и конечный угол, а также внутренний и внешний радиус (полезно для выполнения этих модных круговых диаграмм в стиле пончика). Решение не полагается на аппроксимацию кривой сегментами линии и может быть анимировано в соответствии с примером часов, упомянутым в исходном вопросе.

Сначала создайте область рисования Рафаэля; следующий предполагает DIV с идентификатором «raphael_paper» в вашем HTML файл:

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

к этому объекту Рафаэля добавить пользовательский arc атрибут, функцию, которая принимает центр окружности (х и у координат), A начальный угол, конечный угол, внутренний радиус и внешний радиус:

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}; 
}; 

теперь мы можем использовать это, чтобы нарисовать дуги заданной толщины, начиная и заканчивая там, где мы хотим, чтобы они, например.

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]}); 

Это должно привести к появлению трех сегментов серой дуги с красными, синими и зелеными границами 1px.

+0

Я пытался всплыть, создавая диаграммы пончиков в Рафаэле, и это было именно то, что мне нужно! –

1

Вы также можете сделать это без использования петель. Следующее достигает этого и работает с отрицательными углами.

Проход в объекте Рафаэля как r. Углы начинаются с 0 градусов, что является вершиной круга, а не справа, как было указано в нескольких других решениях.

 function drawArc(r, centerX, centerY, radius, startAngle, endAngle) { 
      var startX = centerX+radius*Math.cos((90-startAngle)*Math.PI/180); 
      var startY = centerY-radius*Math.sin((90-startAngle)*Math.PI/180); 
      var endX = centerX+radius*Math.cos((90-endAngle)*Math.PI/180); 
      var endY = centerY-radius*Math.sin((90-endAngle)*Math.PI/180); 
      var flg1 = 0; 

      if (startAngle>endAngle) 
       flg1 = 1; 
      else if (startAngle<180 && endAngle<180) 
       flg1 = 0; 
      else if (startAngle>180 && endAngle>180) 
       flg1 = 0; 
      else if (startAngle<180 && endAngle>180) 
       flg1 = 0; // edited for bugfix here, previously this was 1 
      else if (startAngle>180 && endAngle<180) 
       flg1 = 1; 

      return r.path([['M',startX, startY],['A',radius,radius,0,flg1,1,endX,endY]]); 
     }; 
2

Для тех, кто хочет дуги должны быть сделаны с замкнутой траектории и не инсульт, я продлил genkilabs ответ, чтобы сделать решение. В случаях, когда вам нужно дать внешний удар вашей дуге, это может помочь.

// Custom Arc Attribute, position x&y, value portion of total, total value, Radius, width 
var archtype = Raphael("canvas", 200, 100); 
archtype.customAttributes.arc = function (xloc, yloc, value, total, R, width) { 
    if(!width) width = R * 0.4; 
    var alpha = 360/total * value, 
     a = (90 - alpha) * Math.PI/180, 
     w = width/2, 
     r1 = R + w, 
     r2 = R - w, 
     x1 = xloc + r1 * Math.cos(a), 
     y1 = yloc - r1 * Math.sin(a), 
     x2 = xloc + r2 * Math.cos(a), 
     y2 = yloc - r2 * Math.sin(a), 
     path; 
    if (total == value) { 
     path = [ 
      ["M", xloc, yloc - r1], 
      ["A", r1, r1, 0, 1, 1, xloc - 0.01, yloc - r1], 
      ["Z"], 
      ["M", xloc - 0.01, yloc - r2], 
      ["A", r2, r2, 0, 1, 0, xloc, yloc - r2], 
      ["Z"] 
     ]; 
    } else { 
     path = [ 
      ["M", xloc, yloc - r1], 
      ["A", r1, r1, 0, +(alpha > 180), 1, x1, y1], 
      ["L", x2, y2], 
      ["A", r2, r2, 0, +(alpha > 180), 0, xloc, yloc - r2], 
      ["L", xloc, yloc - r1], 
      ["Z"] 
     ]; 
    } 
    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({ 
    "fill": "#00f", 
    "stroke": "#f00", 
    "stroke-width": 5, 
    arc: [50, 50, 0, 100, 30] 
}); 

my_arc.animate({ 
    arc: [50, 50, 40, 100, 30] 
}, 1500, "bounce"); 

JSFiddle

1

Я адаптировал genkilabs ответить включает вращение и инверсию способность.Кроме того, количество заполненного кольца было изменено на один процент. (Инверсия была адаптирована от this post). Надеюсь, это полезно!

paper.customAttributes.arc = function (xloc, yloc, percent, rad, rot, invert) { 
    var alpha = 3.6 * percent, 
    a = (90 - alpha) * Math.PI/180, 
    x = xloc + rad * Math.cos(a), 
    y = yloc - rad * Math.sin(a), 
    path; 

    if (invert) { 
     x = xloc - rad * Math.cos(a); 
    } 

    if (percent >= 100) { 
     path = [ 
      ["M", xloc, yloc - rad], 
      ["A", rad, rad, 0, 1, 1, xloc - 0.01, yloc - rad] 
     ]; 
    } else { 
     path = [ 
      ["M", xloc, yloc - rad], 
      ["A", rad, rad, 0, +(alpha > 180), +(!invert), x, y] 
     ]; 
     } 
    return { 
     path: path, 
     transform: "r"+rot+","+xloc+","+yloc, 
    }; 
}; 

 Смежные вопросы

  • Нет связанных вопросов^_^