After drawing Stroke on Canvas, adding a stroke to another object changes all the strokes

Working on a sort of mapping portal. Been using the tutorial: A Gentle Introduction to Making HTML5 Canvas Interactive by @SimonSarris

It’s been going well, yet I have encountered a Path Stroke issue. I have been trying to find where beginPath() needs to be added to ensure that when I select a Shape, the gridlines in the background do not get changed to the same lineWidth value. There is a lot of code thus far, and I have it running here: http://jsfiddle.net/Twisty/me4fkthe/

When I add a shape, I see:
enter image description here

When I select and move the shape, I then see:
enter image description here

Here is the basics to my code:

function rTent(x, y, w, h, fill, lbl) {
    // Rect / Square tent
    this.x = x || 0;
    this.y = y || 0;
    this.w = (w * 10) || 100;
    this.h = (h * 10) || 100;
    this.fc = fill || "rgba(255, 125, 125, 0.65)";
    this.lbl = lbl || "Tent";
    this.sqft = (w * h) || 100;
}

rTent.prototype.draw = function (ctx) {
    ctx.beginPath();
    ctx.fillStyle = this.fc;
    ctx.fillRect(this.x, this.y, this.w, this.h);
    ctx.strokeStyle = "#000";
    ctx.lineWidth = 1.5;
    ctx.strokeRect(this.x, this.y, this.w, this.h);
    console.log("Draw Rect Tent Completed, W:" + this.w + ", L:" + this.h + " (" + this.x + "," + this.y + ") Color: " + this.fc);

    ctx.textBaseLine = "top";
    ctx.textAlign = "center";
    ctx.font = "11px Verdana";
    ctx.fillStyle = "#000";
    ctx.fillText(
    this.lbl, (this.x + this.w / 2), (this.y + this.h / 2) - 14);
    ctx.fillText(
        "SQFT:" + (this.w / 10) * (this.h / 10), (this.x + this.w / 2), (this.y + this.h / 2)
    );
    ctx.closePath();
};

rTent.prototype.contains = function (mx, my) {
    return (this.x <= mx) && (this.x + this.w >= mx) && (this.y <= my) && (this.y + this.h >= my);
};

// skipping CanvasState definition - see jsFiddle ...

CanvasState.prototype.addShape = function (shape) {
    this.shapes.push(shape);
    this.valid = false;
};

CanvasState.prototype.clear = function () {
    this.ctx.clearRect(0, 0, this.width, this.height);
};

// While draw is called as often as the INTERVAL variable demands,
// It only ever does something if the canvas gets invalidated by our code
CanvasState.prototype.draw = function () {
    // if our state is invalid, redraw and validate!
    if (!this.valid) {
        var ctx = this.ctx;
        var shapes = this.shapes;
        this.clear();

        // ** Add stuff you want drawn in the background all the time here **
        // This is where GridLine are redrawn in the background
        this.drawGrid();

        // draw all shapes
        var l = shapes.length;
        for (var i = 0; i < l; i++) {
            var shape = shapes[i];
            // We can skip the drawing of elements that have moved off the screen:
            if (shape.x > this.width || shape.y > this.height || shape.x + shape.w < 0 || shape.y + shape.h < 0) continue;
            shapes[i].draw(ctx);
        }

        // draw selection
        // right now this is just a stroke along the edge of the selected Shape
        if (this.selection !== null) {
            ctx.beginPath();
            ctx.strokeStyle = this.selectionColor;
            ctx.lineWidth = this.selectionWidth;
            var mySel = this.selection;
            ctx.strokeRect(mySel.x, mySel.y, mySel.w, mySel.h);
        }

        // ** Add stuff you want drawn on top all the time here **

        this.valid = true;
    }
};

// More code skipped - see js Fiddle ...

CanvasState.prototype.drawGrid = function () {
    var gridOptions = {
        minorLines: {
            separation: 10,
            color: '#ddd'
        },
        majorLines: {
            separation: 100,
            color: '#ccc'
        },
        majorLabel: {
            font: 'Verdana',
            fontSize: '8px',
            fontColor: '#000'
        }
    };

    this.drawGridLines(gridOptions.minorLines, '');
    this.drawGridLines(gridOptions.majorLines, gridOptions.majorLabel);
};

CanvasState.prototype.drawGridLines = function (lineOptions, labelOptions) {
    var iWidth = this.width;
    var iHeight = this.height;

    var ctx = this.ctx;

    ctx.strokeStyle = lineOptions.color;
    ctx.strokeWidth = 1;

    ctx.beginPath();

    var iCount = null;
    var gc = 0;
    var gi = null;
    var gx = null;
    var gy = null;
    var labelOff = 10;

    iCount = Math.floor(iWidth / lineOptions.separation);
    if (typeof labelOptions !== 'string') {
        ctx.textBaseline = "top";
        ctx.textAlign = "center";
        ctx.font = labelOptions.fontSize + " " + labelOptions.font;
        ctx.fillText("0", 10, 2);
        gc = ((iWidth + 1) / 10);
        ctx.fillText(gc.toString(), iWidth - labelOff, 2);
    }

    for (gi = 1; gi <= iCount; gi += 1) {
        gx = (gi * lineOptions.separation);
        if (typeof labelOptions != 'string') {
            gc = gx / 10;
            ctx.fillText(gc.toString(), gx, 2);
        }
        ctx.beginPath()
        ctx.moveTo(0.5 + gx, labelOff);
        ctx.lineTo(0.5 + gx, iHeight - labelOff + 1);
        ctx.stroke();
    }

    iCount = Math.floor(iHeight / lineOptions.separation);

    if (typeof labelOptions !== 'string') {
        ctx.textBaseline = "middle";
        ctx.textAlign = "left";
        ctx.fillText("0", 2, 11);
        gc = ((iHeight + 1) / 10);
        ctx.fillText(gc.toString(), 0, iHeight - labelOff);
    }

    for (gi = 1; gi <= iCount; gi += 1) {
        gy = (gi * lineOptions.separation);
        if (typeof labelOptions != 'string') {
            gc = gy / 10;
            ctx.fillText(gc.toString(), 0, gy);
        }
        ctx.beginPath();
        ctx.moveTo(labelOff, 0.5 + gy);
        ctx.lineTo(iWidth - labelOff, 0.5 + gy);
        ctx.stroke();
    }

    ctx.closePath();
};

$(function () {
    var s = new CanvasState(document.getElementById('fpCanvas'));
    $("#add_tent_btn").click(function () {
        if ($("#tent_shape_choice").val() == "hex") {
            s.addShape(new hTent(
                120,
                120,
                $("#tent_w").val(),
                50,
                $("#tent_color_choice").val()
            ));
        } else {
            s.addShape(new rTent(
                120,
                120,
                $("#tent_w").val(),
                $("#tent_l").val(),
                $("#tent_color_choice").val()
            ));
        }
    });
});

This happens the moment I select a shape, a stroke is added around the object with lineWidth = 2;. After adding beginPath() to as many places I can think of, it’s still causing the background to change.


Source: html5

Leave a Reply