Jump to content

Fabric.js - Uncaught TypeError: Cannot read properties of undefined (reading 'id') at i.updateNewLineCoordinates


 Share

Recommended Posts

I'm getting this error and I'm not sure what's causing it.  I'm a little newer to JS.  I'm using the fabric framework so to speak.  It takes place on line 101 in the function updateNewLineCoordinates where it says:

Quote

if(obj.id==='added-line') {

I am hoping someone can help me fix the error. 

Here is the code:

let canvas = new fabric.Canvas("canvas", {
    width: window.innerWidth, 
    height: window.innerHeight
});
    
let addingLineBtn = document.getElementById('adding-line-btn'); // DrawBtn is the button pressed
let addingLineBtnClicked = false;

addingLineBtn.addEventListener('click', activateAddingLine); // call function activeAddingLine, then define it later

function activateAddingLine() {
    if(addingLineBtnClicked===false) {  // If you don't set this to false, then each time you click the Draw Line button, you have to also click the Select button or it will draw a new line when dragging another.
        addingLineBtnClicked = true;
        canvas.on('mouse:down', startAddingLine); // when mouse is down call function startAddingLine
        canvas.on('mouse:move', startDrawingLine);
        canvas.on('mouse:up', stopDrawingLine);

        canvas.selection = false;  // this keeps the default selection box turned off.  I want that option only when I choose to have it.
        canvas.hoverCursor = 'auto';  // When hovering over a line, it does not show that default MOVE cursor with 4 arrows.
    
        objectSelectability('added-line', false);
    }    
}

let line; // Make a global variable so it can be called in other functions
let mouseDown = false; // must be set to false so it can be "True" when actually pressed

function startAddingLine(o) {
    mouseDown = true;
    let pointer = canvas.getPointer(o.e);
    
    line = new fabric.Line([pointer.x, pointer.y, pointer.x, pointer.y], { // we need 4 coordinates x,y where the line started, and x,y where it ended   
            id: 'added-line',
            stroke: 'black',
            strokeWidth: 3,
            selectable: false   // Set so you won't drag a drawn line on accident, but the move cursor pops up by default anyway.
        });  
        
        canvas.add(line); // will draw the line
        canvas.requestRenderAll(); // now rend the draw line being drawn
}

function startDrawingLine(o) {
    if(mouseDown===true) {
        let pointer = canvas.getPointer(o.e); 

        line.set({
            x2: pointer.x,
            // x2: Math.round(number / 10) * 10,  // Not sure if this will round to closets 10 or not since line won't draw.
            y2: pointer.y
        });

        canvas.requestRenderAll(); // Will actually render the line drawn
    }
}

function stopDrawingLine() {
    line.setCoords();  // This must be set for fabric to store the location of the line drawn so you can store or select it later.
    mouseDown = false; // set mouseDown to false so it will quit drawing the line
}

let deactivateAddingShapeBtn = document.getElementById('deactivate-adding-shape-btn');

deactivateAddingShapeBtn.addEventListener('click', deactivateAddingShape)

function deactivateAddingShape(){
    canvas.off('mouse:down', startAddingLine); // These functions now turn canvas.off so it will no longer keep drawing.
    canvas.off('mouse:move', startDrawingLine);
    canvas.off('mouse:up', stopDrawingLine);

    objectSelectability('added-line', true);

    canvas.hoverCursor = 'all-scroll';  // set cursor to the drag icon when hovering in area.
    addingLineBtnClicked = false;  // Set to false or you will not be able to draw in the addingActivateLine function.
}

function objectSelectability(id,value) {
    canvas.getObjects().forEach(o => {  // without this little bit of code, original lines drawn will be moveable without hitting the select button and when selecting and moving, it will draw another line.
        if(o.id===id) {                 // this is bascially a bug fix for drawing lines because of the way the buttons we programmed work.
            o.set({                     // Youtube for this reasoning can be found here: https://www.youtube.com/watch?v=IQgeefO849w&list=PL-gIJFyHJjykXg776HNz3H7XXzBMSu5mL&index=4
                selectable: value
            })
        }
    });
}

canvas.on({  // this is so that when you move the line, the dblclick circles on the ends move with it.
    'object:moved': updateNewLineCoordinates,
    'selection:created': updateNewLineCoordinates,
    'selection:updated': updateNewLineCoordinates,
    'mouse:dblclick': addingControlPoints
});

let newLineCoords = {};

function updateNewLineCoordinates(o) {  // this calculates from center of line and uses the offsets of x,y to move editing circles with the line.
    newLineCoords = {};
    
    let obj = o.target;

    if(obj.id==='added-line') {
        let centerX = obj.getCenterPoint().x; // Gets the X coordinate of the center of the line drawn
        let centerY = obj.getCenterPoint().y; // Gets the Y coordinate of the center of the line drawn

        let x1offset = obj.calcLinePoints().x1;  // Now calculate the end beginng and ending of each line to place the red circle for editing the line (so you can drag and make the line bigger or shorter)
        let y1offset = obj.calcLinePoints().y1;
        let x2offset = obj.calcLinePoints().x2;
        let y2offset = obj.calcLinePoints().y2;

        newLineCoords = {  // places circle at the end of each line x1, y1 being the beginning of the line
            x1: centerX+x1offset,
            y1: centerY+y1offset,
            x2: centerX+x2offset,
            y2: centerY+y2offset
        }
    }
}
w
function addingControlPoints(o) {
    let obj = o.target;

    if(!obj) {  // If there is no object, then strokeWidth is not defined so it will throw an error in console.
        return;
    }
    else {
        if(obj.id==='added-line') {  // All lines are given the 'added-line' id so we can select them later.
            let pointer1 = new fabric.Circle({  // These circles are so you can resize the line, there are no defaults for this, so we are creating it.
                radius: obj.strokeWidth*3,
                fill: 'red', 
                opacity: 0.5,
                top: newLineCoords.y1,
                left: newLineCoords.x1,
                originX: 'center',  // these two lines place the red editing circle dead center on the end of the line.
                originY: 'center'
            });
        
            let pointer2 = new fabric.Circle({  // This is the other end of that line we want to resize.
                radius: obj.strokeWidth*3,
                fill: 'red', 
                opacity: 0.5,
                top: obj.y2,
                left: obj.x2,
                originX: 'center',  // these two lines place the red editing circle dead center on the end of the line.
                originY: 'center'
            });
        
            canvas.add(pointer1,pointer2);
            canvas.requestRenderAll();
        }
    }
}

 

Link to comment
Share on other sites

let obj = o.target;

if(obj.id==='added-line') {

According to the docs,

The event handler receives an options object, which has 2 properties: e — the original event, and target — a clicked object on canvas, if any. The event is present at all times, but target only exists if you actually did click on some object on canvas. The target is also only passed to handlers of events where it makes sense. For example, for "mouse:down" but not for "after:render" (which denotes that entire canvas was re-drawn).

  • Great Answer 1
Link to comment
Share on other sites

Hrmmm.... I see.  I was thinking the error was related to the issue where if I draw a line on the canvas, and then double click it, the red circles are supposed to draw at the beginning and ending of the line.  The code to resize the line isn't yet implemented as I've been stuck on why the red circles do not draw when double clicking on the line.

 

Apparently, it's unrelated and so back to the drawing board.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.