简体   繁体   中英

Uncaught TypeError: Cannot read property 'width' of null

I actually don't know what's happened because it was working last night. Anyway, I'm trying to make a drawing application with html5 and javascript. This is the first time I've properly looked at JS and created something with it so I've got my code from various tutorials and help from other friends aka I'm a n00b. I used the following:

  1. github.com/jaseemkp/paint-app-with-save-facility
  2. codetheory.in/different-tools-for-our-sketching-application/
  3. HTML5 Canvas Cookbook - Chapter 6: Interacting with the Canvas: Attaching Event Listeners to Shapes and Regions - Creating a drawing application. (I got the save feature from this)

When I test my work in chrome I get the error

"Uncaught TypeError: Cannot read property 'width' of null"

which refers to line 4 of my script file which is

var b_width = canvas.width, b_height = canvas.height;

I was trying to fiddle around with it to add a text feature but just couldn't get it to work so I just undone everything and now it's producing this error.

Full script:

var canvas = document.getElementById("realCanvas");
var tmp_board = document.getElementById("tempCanvas");
var b_width = canvas.width, b_height = canvas.height;
var ctx = canvas.getContext("2d");
var tmp_ctx = tmp_board.getContext("2d");
var x, y; 
var saved = false, hold = false, fill = false, stroke = true, tool = 'rectangle';

var data = {"rectangle": [], "circle": [], "line": []};


function curr_tool(selected){tool = selected;}

function attributes(){
    if (document.getElementById("fill").checked)
        fill = true;
    else
        fill = false;
    if (document.getElementById("outline").checked)
        stroke = true;
    else
        stroke = false;
}


function clears(){
    ctx.clearRect(0, 0, b_width, b_height);
    tmp_ctx.clearRect(0, 0, b_width, b_height);
    data = {"rectangle": [], "circle": [], "line": []};
}

//colour function
function color(scolor){  
    tmp_ctx.strokeStyle = scolor;
    if (document.getElementById("fill").checked)
        tmp_ctx.fillStyle =  scolor; 
}



//line

tmp_board.onmousedown = function(e) {
    attributes();
    hold = true;
    x = e.pageX - this.offsetLeft;
    y = e.pageY -this.offsetTop;
    begin_x = x;
    begin_y = y;
    tmp_ctx.beginPath();
    tmp_ctx.moveTo(begin_x, begin_y);    
}


tmp_board.onmousemove = function(e) {
    if (x == null || y == null) {
        return;
    }
    if(hold){
        x = e.pageX - this.offsetLeft;
        y = e.pageY - this.offsetTop;
        Draw();
    }
}

tmp_board.onmouseup = function(e) {
    ctx.drawImage(tmp_board,0, 0);
    tmp_ctx.clearRect(0, 0, tmp_board.width, tmp_board.height);
    end_x = x;
    end_y = y;
    x = null;
    y = null;
    Draw();
    hold = false;
}



//draw function
function Draw(){

//rectangle
if (tool == 'rectangle'){

    if(!x && !y){
    data.rectangle.push({"x": begin_x, "y": begin_y, "width": end_x-begin_x, "height": end_y-begin_y, "stroke": stroke, "strk_clr": tmp_ctx.strokeStyle, "fill": fill, "fill_clr": tmp_ctx.fillStyle });
        return;
    }  
    tmp_ctx.clearRect(0, 0, b_width, b_height);
    tmp_ctx.beginPath();

    if(stroke)
        tmp_ctx.strokeRect(begin_x, begin_y, x-begin_x, y-begin_y);
        tmp_ctx.lineWidth = $('#selWidth').val();
    if(fill) 
        tmp_ctx.fillRect(begin_x, begin_y, x-begin_x, y-begin_y);
        tmp_ctx.closePath();

    }

//line

if (tool == 'line'){
    if(!x && !y){
        data.line.push({"x": begin_x, "y": begin_y, "width": end_x-begin_x, "height": end_y-begin_y, "stroke": stroke, "strk_clr": tmp_ctx.strokeStyle,});
        return;
    }  
    tmp_ctx.beginPath();
    if(stroke)
    tmp_ctx.strokeRect(begin_x, begin_y, x-begin_x, y-begin_y);
    tmp_ctx.clearRect(0, 0, tmp_board.width, tmp_board.height);
    tmp_ctx.beginPath();
    tmp_ctx.moveTo(begin_x, begin_y);
    tmp_ctx.lineTo(x, y);
    tmp_ctx.lineWidth = $('#selWidth').val();
    tmp_ctx.stroke();
    tmp_ctx.closePath();

    }

//circle

else if (tool == 'circle'){   
    if(!x && !y){
        data.circle.push({"x": begin_x, "y": begin_y, "radius": end_x-begin_x, "stroke": stroke, "strk_clr": tmp_ctx.strokeStyle, "fill": fill, "fill_clr": tmp_ctx.fillStyle });   
        return;
    }   
    tmp_ctx.clearRect(0, 0, b_width, b_height);
    tmp_ctx.beginPath();
    tmp_ctx.arc(begin_x, begin_y, Math.abs(x-begin_x), 0 , 2 * Math.PI, false);

    if(stroke) 
    tmp_ctx.stroke();
    tmp_ctx.lineWidth = $('#selWidth').val();
    if(fill) 
    tmp_ctx.fill();
    tmp_ctx.closePath();

    }

}

//save function
//set up image of canvas
function getCanvasImg(canvas){
    var img = new Image();
    img.src = canvas.toDataURL();
    return img;
}
//get image of canvas
window.onload = function (){
    var events = new Events("tempCanvas");
    var canvas = events.getCanvas();
    var context = events.getContext();
}
//open image of canvas in new window in click of button
document.getElementById("saveButton").addEventListener("click", function(evt){
    //open new window with saved image, right click and save
    window.open(canvas.toDataURL());
}, false);

Full HTML

<!doctype html>
<html>
<head>
    <title>LogoMakr</title>
    <link rel="stylesheet" href="style.css" type="text/css">
    <script src="jquery.min.js"></script>
    <script src="script.js"> </script>
</style>
</head>
<body>
    <div class="tools">
        <button type="button" id="saveButton" value="Save">Save</button>
        <button type="button" onclick="clears()">CLEAR</button>
        <button type="button" onclick="curr_tool('rectangle')">Rectangle</button>
        <button type="button" onclick="curr_tool('circle')">Circle</button>
        <button type="button" onclick="curr_tool('line')">Line</button>

    </div>

    <table id="table1" >
        <tr>
        <tr>
            <td><button onclick="color('black')" style="background-color: black; height: 20px; width: 20px;"></button></td>
            <td><button onclick="color('white')" style="background-color: white; height: 20px; width: 20px;"></button></td>
            <td><button onclick="color('green')" style="background-color: green; height: 20px; width: 20px;"></button></td>
            <td><button onclick="color('blue')" style="background-color: blue; height: 20px; width: 20px;"></button></td>
            <td><button onclick="color('yellow')" style="background-color: yellow; height: 20px; width: 20px;"></button></td>
            <td><button onclick="color('red')" style="background-color: red; height: 20px; width: 20px;"></button></td>
            <td><button onclick="color('#ff6600')" style="background-color: #ff6600; height: 20px; width: 20px;"></button></td>
            <td><button onclick="color('#663300')" style="background-color: #663300; height: 20px; width: 20px;"></button></td>
            <td><button onclick="color('grey')" style="background-color: grey; height: 20px; width: 20px;"></button></td>
            <td><button onclick="color('#FF6699')" style="background-color: #FF6699; height: 20px; width: 20px;"></button></td>
            <td><button onclick="color('#8b00ff')" style="background-color: #8b00ff; height: 20px; width: 20px;"></button></td>
            <td><input type="checkbox" id="fill"/>Fill</td>
            <td><input type="checkbox" id="outline" checked="checked"/>Outline</td>

            <td>Line Width:</td>
            <td><select id="selWidth">
                    <option value="1">1</option>
                    <option value="3">3</option>
                    <option value="5" selected="selected">5 </option>
                    <option value="7">7</option>
                    <option value="9" >9</option>
                    <option value="11">11</option>
                    </select>
            </td>
        </tr>
    </table>


    <div>
        <canvas id="realCanvas" width="680" height="460" style=" background-color: #ffffff; z-index: 0"  ></canvas>
        <canvas id="tempCanvas" width="680" height="460"  style="z-index: 1"></canvas>
    </div>  



</body>
</html>

CSS

#realCanvas, #tempCanvas {
    position: absolute;
    left:280px;
    top:50px;
    border: 5px solid;
    cursor: crosshair;
}



#table1{
    position: absolute;
    left:400px;
    top:5px; 
}

When I've uploaded it to a free server , I've got different errors though. Oh I'm so confused, I hope there's someone out there that can make sense of it all :/

Thanks in advance!

You're importing your script before the browser has had a chance to parse the document body. As such, the <canvas> element doesn't exist at the point you seek it by its "id" value.

Since you're importing jQuery anyway, you can employ a "ready" handler, but then you'll have some issues with the way you're attaching event handlers. Your attribute-based event handlers rely on those handler functions being global, which they won't be if you put them in a "ready" handler.

Much simpler, however, would be to simply move your <script> tag (or both of them) to the very end of the <body> . That way the DOM will be parsed and your getElementById() calls should work. Lots of people advise that putting scripts at the end of the <body> should be considered a best practice anyway.

Failing that, I suppose what you could do is something like this, changing the declarations at the top of your script:

$(function() {
  $.extend(window, {
    canvas: document.getElementById("realCanvas"),
    tmp_board: document.getElementById("tempCanvas"),
    b_width: canvas.width, b_height = canvas.height,
    ctx: canvas.getContext("2d"),
    tmp_ctx: tmp_board.getContext("2d"),
    x: undefined,
    y: undefined,
    saved: false,
    hold: false,
    fill: false,
    stroke: true,
    tool: 'rectangle',
    data: {"rectangle": [], "circle": [], "line": []}
  });
});

It'd be better to either adopt jQuery fully and use it to assign event handlers, or else just don't bother importing it.

You can also add defer attribute on SCRIPT elements. It instructs the contents of the script tag to not execute until the page has loaded.

So you'll have something like this:

<script src="myscript.js" defer></script>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM