javascriptcssfabricjs

Fabric "Rect" object is placed outside the "div" element of its "canvas" element


I'm working with Fabric js and I'm having a problem with a "rect" object. With the following structure of my page:

<div id="div0">
    <div id="divDespl"></div>
    <div id="divCont">
        <div id="divIz"></div>
        <div id="div1" >
            <canvas id="micanvas"></canvas>
        </div>
    </div>
</div>

The "rect" object is placed outside of the "div1" div (which is the div containing the "micanvas" canvas that the "rect" object is supposed to be added to).

The result looks like this:

image

The rectangle is below.

When I use a simple structure like this:

<div id="div1" >
    <canvas id="micanvas"></canvas>
</div>

The rectangle does appear placed in the div "div1". It looks like this.

image

The function that does the work with javascript is the following:

function Canvas2(nombrearchivo) {
       
        let di = document.getElementById("div1");
       
        di.style.backgroundImage = "url('/google/archivosdescargados/" + nombrearchivo + "')";     
        $("#div1").css("background-size", "contain");
        $("#div1").css("background-repeat", "no-repeat");  
       
        const canvas = new fabric.Canvas(micanvas);      

        // create a rect object
        const deleteIcon =
            "data:image/svg+xml,%3C%3Fxml version='1.0' encoding='utf-8'%3F%3E%3C!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'%3E%3Csvg version='1.1' id='Ebene_1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' width='500.275px' height='500.275px' viewBox='200 215 230 470' xml:space='preserve'%3E%3Ccircle style='fill:%23F44336;' cx='299.76' cy='439.067' r='218.516'/%3E%3Cg%3E%3Crect x='267.162' y='307.978' transform='matrix(0.7071 -0.7071 0.7071 0.7071 -222.6202 340.6915)' style='fill:white;' width='65.545' height='262.18'/%3E%3Crect x='266.988' y='308.153' transform='matrix(0.7071 0.7071 -0.7071 0.7071 398.3889 -83.3116)' style='fill:white;' width='65.544' height='262.179'/%3E%3C/g%3E%3C/svg%3E";

        var deleteImg = document.createElement('img');
        deleteImg.src = deleteIcon;

        fabric.Object.prototype.transparentCorners = false;
        fabric.Object.prototype.cornerColor = 'blue';
        fabric.Object.prototype.cornerStyle = 'circle';

        const rect = new fabric.Rect({
            left: 100,
            top: 50,
            width: 200,
            height: 100,
            objectCaching: false,
            stroke: 'lightgreen',
            strokeWidth: 4            
        });
        rect.controls.deleteControl = new fabric.Control({
            x: 0.5,
            y: -0.5,
            offsetY: 16,
            cursorStyle: 'pointer',
            mouseUpHandler: deleteObject,
            render: renderIcon,
            cornerSize: 24,
        });
        canvas.add(rect);
        canvas.setActiveObject(rect);


        function deleteObject(_eventData, transform) {
            const canvas = transform.target.canvas;
            canvas.remove(transform.target);
            canvas.requestRenderAll();

        }

        function renderIcon(ctx, left, top, _styleOverride, fabricObject) {
            const size = this.cornerSize;
            ctx.save();
            ctx.translate(left, top);
            ctx.rotate(fabric.util.degreesToRadians(fabricObject.angle));
            ctx.drawImage(deleteImg, -size / 2, -size / 2, size, size);
            ctx.restore();

        }
}

The CSS style code is as follows:

  <style type="text/css">
         html, body {
             height: 100%; margin: 0; width: 100%;
         }
         
         /* html {padding-top: 1%;} */
          #div0 {  
             height: 100%;
             width: 100%;
             background-color: red;
         }
           #divDespl {            
             height: 3%;
             width: 100%;
             background-color: yellow;
         }
            #divCont {            
             display: inline-block;
             height: 97%;
             width: 100%;
             background-color: orange;
         }
            #divIz {            
             height: 97%;
             width: 3%;
             background-color: navajowhite;
             float: left;             
         }
         #div1 {            
             display: block;
             justify-content: center;
             align-items: center;
             height: 97%;
             width: 94%;
             background-color: blue;
             z-index: 1
         }
          #divDe {            
             height: 97%;
             width: 3%;
             background-color: black;
             float: right;
             display: inline;
             
         }

         </style>

I wonder what could be the reason why when placing a more complex structure the rectangle comes out. At first it seems that it must be due to the CSS attributes of the elements, but I can't find which one or which ones.

The image is as a background image in the div "div1" with "background-size" as "contain". I don't think that can affect it.


Solution

  • The summary: You have tried to make too many <div>s have height of 100% (and 97%). So not everything fits vertically, causing one of fabric's canvas's to move down.

    The simple fix is to remove the divIz <div>.

    The longer explanation: fabric.js creates a second <canvas> with position relative. That is relative to what would be it's normal position on the page. Your 97% height on the divIz <div> moves that normal position way down the page.

    To see what is going on in your original code, apply a css border around canvas elements and you will see the second canvas at the bottom of the page. You can also use your browser's debug environment and inspect the canvas element to see there are two and the positioning that fabric has applied to them.

    NOTE: If you want to keep the full height divIz, you can remove it's css width and add the following two lines to the divCont css:

      display: grid;
      grid-template-columns: 3% auto;
    

    Canvas2("")
    
    function Canvas2(nombrearchivo) {
           
            let di = document.getElementById("div1");
           
            // EDIT For demo
            // di.style.backgroundImage = "url('/google/archivosdescargados/" + nombrearchivo + "')";
            di.style.backgroundImage = "url('https://placebear.com/800/300.jpg')";
            
            $("#div1").css("background-size", "contain");
            $("#div1").css("background-repeat", "no-repeat");  
           
            const canvas = new fabric.Canvas(micanvas);      
    
            // create a rect object
            const deleteIcon =
                "data:image/svg+xml,%3C%3Fxml version='1.0' encoding='utf-8'%3F%3E%3C!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'%3E%3Csvg version='1.1' id='Ebene_1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' width='500.275px' height='500.275px' viewBox='200 215 230 470' xml:space='preserve'%3E%3Ccircle style='fill:%23F44336;' cx='299.76' cy='439.067' r='218.516'/%3E%3Cg%3E%3Crect x='267.162' y='307.978' transform='matrix(0.7071 -0.7071 0.7071 0.7071 -222.6202 340.6915)' style='fill:white;' width='65.545' height='262.18'/%3E%3Crect x='266.988' y='308.153' transform='matrix(0.7071 0.7071 -0.7071 0.7071 398.3889 -83.3116)' style='fill:white;' width='65.544' height='262.179'/%3E%3C/g%3E%3C/svg%3E";
    
            var deleteImg = document.createElement('img');
            deleteImg.src = deleteIcon;
    
            fabric.Object.prototype.transparentCorners = false;
            fabric.Object.prototype.cornerColor = 'blue';
            fabric.Object.prototype.cornerStyle = 'circle';
    
            const rect = new fabric.Rect({
                left: 100,
                top: 50,
                width: 200,
                height: 100,
                objectCaching: false,
                stroke: 'lightgreen',
                strokeWidth: 4            
            });
            rect.controls.deleteControl = new fabric.Control({
                x: 0.5,
                y: -0.5,
                offsetY: 16,
                cursorStyle: 'pointer',
                mouseUpHandler: deleteObject,
                render: renderIcon,
                cornerSize: 24,
            });
            canvas.add(rect);
            canvas.setActiveObject(rect);
    
    
            function deleteObject(_eventData, transform) {
                const canvas = transform.target.canvas;
                canvas.remove(transform.target);
                canvas.requestRenderAll();
    
            }
    
            function renderIcon(ctx, left, top, _styleOverride, fabricObject) {
                const size = this.cornerSize;
                ctx.save();
                ctx.translate(left, top);
                ctx.rotate(fabric.util.degreesToRadians(fabricObject.angle));
                ctx.drawImage(deleteImg, -size / 2, -size / 2, size, size);
                ctx.restore();
    
            }
    }
    /* EDIT Debug */
    canvas {
      outline: solid 4px cyan;
    }
    
     
             html, body {
                 height: 100%; margin: 0; width: 100%;
             }
             
             /* html {padding-top: 1%;} */
              #div0 {  
                 height: 100%;
                 width: 100%;
                 background-color: red;
             }
               #divDespl {            
                 height: 3%;
                 width: 100%;
                 background-color: yellow;
             }
                #divCont {            
                 display: inline-block;
                 height: 97%;
                 width: 100%;
                 background-color: orange;
             }
                #divIz {            
                 height: 97%;
                 width: 3%;
                 background-color: navajowhite;
                 float: left;             
             }
             #div1 {            
                 display: block;
                 justify-content: center;
                 align-items: center;
                 height: 97%;
                 width: 94%;
                 background-color: blue;
                 z-index: 1
             }
              #divDe {            
                 height: 97%;
                 width: 3%;
                 background-color: black;
                 float: right;
                 display: inline;
                 
             }
    <script src="https://cdn.jsdelivr.net/npm/fabric@latest/dist/index.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
    
    <div id="div0">
        <div id="divDespl"></div>
        <div id="divCont">
    <!--        <div id="divIz"></div>
      -->
            <div id="div1" >
                <canvas id="micanvas"></canvas>
            </div>
        </div>
    </div>