2

I'm trying to draw some charts on a Canvas Area. My Problem is following...

I have 1-4 (or more) circles to draw. The canvas size is like 500 x 400 px. How can i now calculate the max Radius of each circle to place all on this canvas and get the position (center x/y) of each circle? So each circle could be optimal placed on the area with some margin to each other?

here some example screens to show you what i mean...

placing four circles Place the circles like a table

thanks a lot!

HR123
  • 688
  • 1
  • 6
  • 15

3 Answers3

2

To calculate the maximum radius you can use

    var numberOfSections = 4;
    var width = 500;
    var height = 400;
    var R = Math.sqrt((width * height) / numberOfSections) / 2

    var MX = Math.round(width / (R * 2)); // max amount of squares that can fit on the width
    var MY = Math.round(height / (R * 2)); // max amount of squares that can fit on the height

var skipLast = 0;
var numOfCalculatedCircles = MX*MY;
if(numOfCalculatedCircles != numberOfSections) {

    if(numOfCalculatedCircles < numberOfSections) {
        console.log('numOfCalculatedCircles',numOfCalculatedCircles);
        MX = MX + Math.ceil((numberOfSections - numOfCalculatedCircles)/MY);
        if(MX*MY != numberOfSections) {
            skipLast = Math.abs(MX*MY - numberOfSections);
        }
    } else {
        skipLast = numOfCalculatedCircles - numberOfSections;;
    }

    console.log('MX*MY',MX*MY);
}
// recalculate the radius for X
if (R * 2 * MX > width) {
    R = (width/2) / MX;
}

// recalculate the radius for Y
if (R * 2 * MY > height) {
    R = (height/2) / MY
}

Calculate the margins for X and Y:

    var circlesWidth = R * 2 * MX;
    var circlesHeight = R * 2 * MY;

    var marginX = 0;
    var marginY = 0;
    if (circlesWidth < width) {
        marginX = (width - circlesWidth) / 2
    }
    if (circlesHeight < height) {
        marginY = (height - circlesHeight) / 2
    }

After that you can calculate the centers:

var RY = marginY + R;
var radiusPadding = 10;

for (var i = 0; i < MY; i++) {
    var RX = marginX + R;
    for (var j = 0; j < MX; j++) {
        if(i === MY - 1) {
          if(j === MX - skipLast) {
            break;
          }
        }
        canvas.drawArc({
            fromCenter: true,
            strokeStyle: 'red',
            strokeWidth: 1,
            start: 0,
            end: 360,
            radius: R - radiusPadding,
            x: RX,
            y: RY
        });

        RX += 2 * R;
    }

    RY += 2 * R;
}

Hope this helps.

UPDATE: It is still incomplete but it may work in this particular example: http://jsfiddle.net/dhM96/4/

lexmihaylov
  • 717
  • 3
  • 8
  • looks interesting but i don't know how to modify it. i've tried following but it draws 6 circles with a to big radius and wrong positions. var numberOfSections = data.length, // currently: 4 R = Math.sqrt((cWidth * cHeight) / numberOfSections) / 2, centers = []; for( var x = R, y = R; ; x += 2 * R ) { if(x >= cWidth) { x = R; y += R; if( y >= cHeight ) break; } canvas.drawArc({ fromCenter: true, strokeStyle: strokeStyle, strokeWidth: strokeWidth, start: 0, end: 360, radius: R, x: x, y: y }); } – HR123 Jul 25 '14 at 08:48
  • @HR123 sorry this answer is incomplete and it's more complex to answer you question than i thought. I've created a jsfiddle that you can use as a reference: http://jsfiddle.net/hn7u7/3/. If this works for you, I will update my answer. – lexmihaylov Jul 25 '14 at 09:51
  • thank you very much!!! it's very difficult... you've done great work. but there's a small problem... if you change the numberOfSections to 2 or 5 or something like it doesn't work anymore... i've tried to round the numbers but your code/math is to difficult for me... hope you can help me another time with this last step. thanks a lot – HR123 Jul 25 '14 at 12:23
1

You are not giving enough of your placement constraints.

Anyway, assuming a free space of F pixels along the rectangle edges and f between the circles, the maximum radius on X is Rx = (Width - 2 F - (Nx-1) f) / 2 and on Y, R y = (Height - 2F - (Ny-1) f) / 2. (Nx circles horizontally, Ny vertically.) Take the smallest of the two.

The centers will be at (F + (2 Rx + f) Ix + Rx, F + (2 Ry + f) Iy + Ry), 0 <= Ix < Nx, 0 <= Iy < Ny.

-1

The Knapsack problem you are asking about is hard to solve. Best approach in your case is to use a given table such as http://www.packomania.com. If you can, restrict yourself to a square.

sina72
  • 4,931
  • 3
  • 35
  • 36
  • thanks for your quick answer. thats to complex i think. maybe the new image above is more helpful. i want to place them like a table. – HR123 Jul 25 '14 at 08:02
  • The problem has nothing to do with the knapstack. It's a packing problem ! http://en.wikipedia.org/wiki/Packing_problem. And the instance of the problem queried by the OP is plain trivial. –  Jul 26 '14 at 07:53
  • I answered the original question. Only after editing it got that trivial. – sina72 Jul 26 '14 at 09:14