0

I am trying to draw a box around multiple shapes in canvas to say that those shapes are related like a group. Tried as below :

var ctx = c.getContext("2d"),
radius = 10,
rect = c.getBoundingClientRect(),

ctx.fillText("Draw something here..", 10, 10);
ctx.fillStyle = "red";
ctx.beginPath();
ctx.arc(250, 300, radius, 0, 6.28);
ctx.fill();
ctx.fillStyle = "yellow";
ctx.beginPath();
ctx.arc(200, 100, radius, 0, 10.28);
ctx.fill();
ctx.fillStyle = "brown";
ctx.beginPath();
ctx.arc(350, 210, radius, 0, 10.28);
ctx.fill();

var x = (250+200+350)/3;
var y = (300+100+210)/3;

var radius = Math.sqrt((x1*x1)+(y1*y1));
var _minX = x - radius;
var _minY = y - radius;
var _maxX = x + radius;
var _maxY = y + radius;

ctx.rect(_minX,_minY,(_maxX-_minX+2),(_maxY-_minY+2));
ctx.stroke();

But it is not drawing properly. How to get bounding box coordinates for canvas content? this link explains only for the path not for the existing shapes. Below is the image how I want to draw: enter image description here

Sowmya
  • 453
  • 1
  • 5
  • 18
  • What exactly is the problem is seems to work? – winner_joiner May 04 '18 at 04:50
  • No - that image is how I want , not the result I got – Sowmya May 04 '18 at 05:06
  • Your code doesn't reflect the shapes you want to be drawn, so it's hard to give you a proper solution for your case. But basically, you would have to store all your shape's BBox in an Array, and then simply get the min_x, max_x, min_y, max_y of all these BBox. This will be the four corners of your group-rect. – Kaiido May 04 '18 at 08:44
  • how can I get BBox for each shape? I have only x,y for all those shapes – Sowmya May 04 '18 at 08:56
  • Can you please help me with the solution or any reference ? – Sowmya May 04 '18 at 08:57
  • Possible duplicate of [How to get bounding box coordinates for canvas content?](https://stackoverflow.com/questions/46528123/how-to-get-bounding-box-coordinates-for-canvas-content) – winner_joiner May 04 '18 at 11:24
  • The searched solution could be this https://stackoverflow.com/a/46528425/1679286 – winner_joiner May 04 '18 at 11:25
  • I have tried those two references. But that is only for the path. But I want to draw for the existing shapes not the path – Sowmya May 06 '18 at 04:38
  • Hi Kaiido... I tried min_x min_y max_x max_y concept and drew rect in canvas. Thank you very much . Now I am trying the same thing to draw as a polygon . Can you please help me? – Sowmya May 17 '18 at 14:37

3 Answers3

0

Fabric <-- See if this library helps had used this for one of my project it is simple and quick.

BlackBurn027
  • 592
  • 4
  • 20
0

This Code is not production ready, Or the best solution, but it works in "most cases".

I'm using the imageData, to check for non-white pixel. (If NOT 0 - RGBA Pixel ==> Object) and with this it narrows the possible Rectangle down. You would also need to tweak it, if you don't want the text to be in the Rectangle.

This code could / should be optimized.

EDIT: Now I am only checking if an Alpha Value is set. And some Random Object creation to test multiple Outcomes

Info: Objects that are clipped/cut happen, because they are out of the canvas size.

var c = document.getElementById("canvas");
var ctx = c.getContext("2d");
var colors = ["red", "blue", "green", "black"];

ctx.fillText("Draw something here..", 0, 10);

/** CREATEING SOME RANDOM OBJECTS (JUST FOR TEST) **/
createRandomObjects();

function createRandomIntMax(max){
 return parseInt(Math.random() * 1000 * max) % max + 1;
}

function  createRandomObjects(){
 var objectsToDraw = createRandomIntMax(20);
 for(var idx = 0; idx < objectsToDraw; idx++){
  ctx.fillStyle = colors[createRandomIntMax(colors.length)];
  ctx.beginPath();
  ctx.arc(createRandomIntMax(c.width), createRandomIntMax(c.height), createRandomIntMax(30), 0, 2 * Math.PI);
  ctx.fill();
 }
}


/** GETTING IMAGE DATA **/
var myImageData = ctx.getImageData(0, 0, c.width, c.height);

/** FINDING BORDERS **/
findBorders(myImageData.data);

function findBorders(imageData) {

    var result = {
        left: c.width,
        top: c.height,
        right: -1,
        bottom: -1
    }

    var idx = 0;
    var lineLow = -1;
    var lineHigh = -1;
    var currentLine = 0;
    var currentPoint, helper;
    while (idx < imageData.length) {
        currentPoint = imageData[idx + 3]; 

        /** CHECKING FOR OBJECT **/
        if (currentPoint != 0) {

            helper = parseInt(idx % (c.width * 4)) / 4;
            if (lineLow < 0) {
                lineLow = helper;
                lineHigh = helper;
            } else {
                lineHigh = helper;
            }
        }

        if (idx !== 0 && (idx % (c.width * 4)) === 0) {
            currentLine = idx / (c.width * 4);
            // Updating the Border Points
            if (lineLow > -1) {
                result.left = Math.min(lineLow, result.left);
                result.top = Math.min(currentLine, result.top);
                result.right = Math.max(lineHigh, result.right);
                result.bottom = Math.max(currentLine, result.bottom);
            }

            lineLow = -1;
            lineHigh = -1;
        }

        idx += 4;
    }

    ctx.rect(result.left, result.top, result.right - result.left, result.bottom - result.top);
    ctx.stroke()

}
<canvas id="canvas"></canvas>
winner_joiner
  • 12,173
  • 4
  • 36
  • 61
-1

USE getBoundingClientRect() to get the exact boundaries

David P
  • 24
  • 3
  • getBoundingClientRect() of which element? Tried using for canvas . Not sure about the logic for selected shapes :( – Sowmya May 04 '18 at 05:19