未捕获的TypeError:无法读取null的属性“width”

时间:2013-05-12 15:38:41

标签: javascript html5 canvas

我实际上不知道发生了什么事,因为它昨晚正在运作。无论如何,我正在尝试使用html5和javascript制作绘图应用程序。这是我第一次正确地看待JS并用它创建了一些东西,所以我从各种教程中得到了我的代码,并得到了其他朋友的帮助a.k.a我是一个n00b。我使用了以下内容:

  1. github.com/jaseemkp/paint-app-with-save-facility
  2. codetheory.in/different-tools-for-our-sketching-application /
  3. HTML5 Canvas Cookbook - 第6章:与Canvas交互: 将事件监听器附加到形状和区域 - 创建图形 应用。 (我从中获得了保存功能)
  4. 当我在chrome中测试我的工作时,我收到了错误

      

    “未捕获的TypeError:无法读取null的属性'width'

    指的是我的脚本文件的第4行

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

    我试图摆弄它以添加文本功能,但是无法让它工作,所以我只是撤消所有内容,现在它产生了这个错误。

    完整脚本:

    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);
    

    完整的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; 
    }
    

    当我将其上传到free server时,我遇到了不同的错误。哦,我很困惑,我希望有人可以理解这一切:/

    提前致谢!

2 个答案:

答案 0 :(得分:5)

您正在导入脚本之前浏览器有机会解析文档正文。因此,<canvas>元素在您通过其“id”值寻找它时不存在。

由于你还在导入jQuery,你可以使用一个“就绪”处理程序,但是你在附加事件处理程序的方式上会遇到一些问题。基于属性的事件处理程序依赖于那些全局的处理程序函数,如果将它们放在“就绪”处理程序中,它们就不会存在。

然而,更简单的方法是将<script>标记(或两者)移动到<body>的最后。这样就可以解析DOM了,你的getElementById()调用应该可行。很多人都建议将脚本放在<body>的末尾应该被视为最佳实践。

如果做不到这一点,我想你可以做的就是这样,改变你脚本顶部的声明:

$(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": []}
  });
});

最好完全采用jQuery并使用它来分配事件处理程序,否则就不用费心去导入它了。

答案 1 :(得分:0)

您还可以在SCRIPT元素上添加defer属性。它指示脚本标签的内容要在页面加载后才能执行。

因此,您将得到以下内容:

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