0

I create a paint application using HTML5 canvas. I do use a background image. But with eraser. When I delete it, the next image is also deleted. Who can help me?

This HTML :

<form>
    <div>
        <label for="pencil">Pencil</label>
        <input id="pencil" type="radio" name="tool" value="pencil" checked>
    </div>

    <div>
        <label for="eraser">Eraser</label>
        <input id="eraser" type="radio" name="tool" value="eraser">
    </div>
</form>

<div id="sketch">
    <canvas id="paint"></canvas>
</div>

And Javascript:

    (function() {

    var canvas = document.querySelector('#paint');
    var ctx = canvas.getContext('2d');

    var sketch = document.querySelector('#sketch');
    var sketch_style = getComputedStyle(sketch);
    canvas.width = parseInt(sketch_style.getPropertyValue('width'));
    canvas.height = parseInt(sketch_style.getPropertyValue('height'));


    // draw image
    var img = new Image();
    img.src = 'http://cssdeck.com/uploads/media/items/3/3yiC6Yq.jpg';
    canvas.width = img.width;
    canvas.height = img.height;
    ctx.drawImage(img, 0, 0);


    // Determine Tool
    var tool = 'pencil';
    document.querySelector('#pencil').onchange = function() {
        if (this.checked)
            tool = 'pencil';

        // Show Tmp Canvas
        tmp_canvas.style.display = 'block';
    };
    document.querySelector('#eraser').onchange = function() {
        if (this.checked)
            tool = 'eraser';

        // Hide Tmp Canvas
        tmp_canvas.style.display = 'none';
    };


    // Creating a tmp canvas
    var tmp_canvas = document.createElement('canvas');
    var tmp_ctx = tmp_canvas.getContext('2d');
    tmp_canvas.id = 'tmp_canvas';
    tmp_canvas.width = canvas.width;
    tmp_canvas.height = canvas.height;

    sketch.appendChild(tmp_canvas);

    var mouse = {x: 0, y: 0};
    var last_mouse = {x: 0, y: 0};

    // Pencil Points
    var ppts = [];

    /* Mouse Capturing Work */
    tmp_canvas.addEventListener('mousemove', function(e) {
        mouse.x = typeof e.offsetX !== 'undefined' ? e.offsetX : e.layerX;
        mouse.y = typeof e.offsetY !== 'undefined' ? e.offsetY : e.layerY;
    }, false);

    canvas.addEventListener('mousemove', function(e) {
        mouse.x = typeof e.offsetX !== 'undefined' ? e.offsetX : e.layerX;
        mouse.y = typeof e.offsetY !== 'undefined' ? e.offsetY : e.layerY;
    }, false);


    /* Drawing on Paint App */
    tmp_ctx.lineWidth = 5;
    tmp_ctx.lineJoin = 'round';
    tmp_ctx.lineCap = 'round';
    tmp_ctx.strokeStyle = 'blue';
    tmp_ctx.fillStyle = 'blue';

    tmp_canvas.addEventListener('mousedown', function(e) {
        tmp_canvas.addEventListener('mousemove', onPaint, false);

        mouse.x = typeof e.offsetX !== 'undefined' ? e.offsetX : e.layerX;
        mouse.y = typeof e.offsetY !== 'undefined' ? e.offsetY : e.layerY;

        ppts.push({x: mouse.x, y: mouse.y});

        onPaint();
    }, false);

    tmp_canvas.addEventListener('mouseup', function() {
        tmp_canvas.removeEventListener('mousemove', onPaint, false);

        ctx.globalCompositeOperation = 'source-over';

        // Writing down to real canvas now
        ctx.drawImage(tmp_canvas, 0, 0);
        // Clearing tmp canvas
        tmp_ctx.clearRect(0, 0, tmp_canvas.width, tmp_canvas.height);

        // Emptying up Pencil Points
        ppts = [];
    }, false);

    var onPaint = function() {

        // Saving all the points in an array
        ppts.push({x: mouse.x, y: mouse.y});

        if (ppts.length < 3) {
            var b = ppts[0];
            tmp_ctx.beginPath();
            //ctx.moveTo(b.x, b.y);
            //ctx.lineTo(b.x+50, b.y+50);
            tmp_ctx.arc(b.x, b.y, tmp_ctx.lineWidth / 2, 0, Math.PI * 2, !0);
            tmp_ctx.fill();
            tmp_ctx.closePath();

            return;
        }

        // Tmp canvas is always cleared up before drawing.
        tmp_ctx.clearRect(0, 0, tmp_canvas.width, tmp_canvas.height);

        tmp_ctx.beginPath();
        tmp_ctx.moveTo(ppts[0].x, ppts[0].y);

        for (var i = 1; i < ppts.length - 2; i++) {
            var c = (ppts[i].x + ppts[i + 1].x) / 2;
            var d = (ppts[i].y + ppts[i + 1].y) / 2;

            tmp_ctx.quadraticCurveTo(ppts[i].x, ppts[i].y, c, d);
        }

        // For the last 2 points
        tmp_ctx.quadraticCurveTo(
            ppts[i].x,
            ppts[i].y,
            ppts[i + 1].x,
            ppts[i + 1].y
        );
        tmp_ctx.stroke();

    };


    canvas.addEventListener('mousedown', function(e) {
        canvas.addEventListener('mousemove', onErase, false);

        mouse.x = typeof e.offsetX !== 'undefined' ? e.offsetX : e.layerX;
        mouse.y = typeof e.offsetY !== 'undefined' ? e.offsetY : e.layerY;

        ppts.push({x: mouse.x, y: mouse.y});

        onErase();
    }, false);

    canvas.addEventListener('mouseup', function() {
        canvas.removeEventListener('mousemove', onErase, false);

        // Emptying up Pencil Points
        ppts = [];
    }, false);

    var onErase = function() {

        // Saving all the points in an array
        ppts.push({x: mouse.x, y: mouse.y});

        ctx.globalCompositeOperation = 'destination-out';
        ctx.fillStyle = 'rgba(0,0,0,1)';
        ctx.strokeStyle = 'rgba(0,0,0,1)';
        ctx.lineWidth = 5;

        if (ppts.length < 3) {
            var b = ppts[0];
            ctx.beginPath();
            //ctx.moveTo(b.x, b.y);
            //ctx.lineTo(b.x+50, b.y+50);
            ctx.arc(b.x, b.y, ctx.lineWidth / 2, 0, Math.PI * 2, !0);
            ctx.fill();
            ctx.closePath();

            return;
        }

        // Tmp canvas is always cleared up before drawing.
        // ctx.clearRect(0, 0, canvas.width, canvas.height);

        ctx.beginPath();
        ctx.moveTo(ppts[0].x, ppts[0].y);

        for (var i = 1; i < ppts.length - 2; i++) {
            var c = (ppts[i].x + ppts[i + 1].x) / 2;
            var d = (ppts[i].y + ppts[i + 1].y) / 2;

            ctx.quadraticCurveTo(ppts[i].x, ppts[i].y, c, d);
        }

        // For the last 2 points
        ctx.quadraticCurveTo(
            ppts[i].x,
            ppts[i].y,
            ppts[i + 1].x,
            ppts[i + 1].y
        );
        ctx.stroke();

    };

}());

Link DEMO : DEMO

JohnEvans
  • 35
  • 1
  • 8
  • Maybe this will help you .. http://stackoverflow.com/questions/7576755/how-to-undraw-hide-remove-or-delete-an-image-from-an-html-canvas –  Oct 19 '13 at 07:44
  • Thank you so much. But it does not work for me. – JohnEvans Oct 19 '13 at 11:01

2 Answers2

1

If you don't want the background image erased, set your image as a background of your container div (#sketch) instead of drawing it on the canvas itself.

// create a url string of your background image

bkImageURL="url(http://cssdeck.com/uploads/media/items/3/3yiC6Yq.jpg)";

// set the background-image of your container div to that url

sketch.style.backgroundImage = bkImageURL;
markE
  • 102,905
  • 11
  • 164
  • 176
  • 1
    Thanks. But can't save canvas with image. :(. I'm want save canvas with image. Any ideas? – JohnEvans Oct 20 '13 at 04:04
  • After erasing done. And image save results : https://lh3.googleusercontent.com/-BxIEHQPKixM/UmNyvgXcTjI/AAAAAAAAADE/S96MT4UVL2M/w640-h320-no/index.png – JohnEvans Oct 20 '13 at 06:08
  • Yes, you can do this...When you are done drawing/erasing and are ready to save the image+drawing, you can draw the background image "under" your final drawing like this: ctx.globalCompositeOperation="destination-over"; ctx.drawImage(yourBackgroundImage,0,0); The result will be your final drawings over the background image. – markE Oct 20 '13 at 07:25
0
  1. Create two canvas elements with different IDs. For this example, let's call the first canvas (or bottom layer) 'background' and the second canvas (or top layer) 'sketchpad':

  2. Use CSS to position one directly over the other. Remember to specify z-values and make 'sketchpad' element a higher value. You can search StackOverflow if you need help completing this step.

  3. Draw your background image onto the 'background' canvas. Here is some sample code:

    // specify background canvas element bgCanvas = document.getElementbyId('background'); // specify canvas context ctx = bgCanvas.getContext('2d');

    // create new background image var bgImg = new Image();

    // draw background image on background canvas bgImg.onload = function () { //draw background image ctx.drawImage(bgImg, 0, 0); } bgImg.src = './path/to/image/file';

  4. Use the 'sketchpad' canvas for your draw / erase functions.

TLT-Dave
  • 14
  • 1
  • 3
  • 1
    did you notice this question was asked and answered over 6 years ago?? The answer (from someone with 89k rep by the way) was accepted. If your answer is better or the accepted answer is no longer applicable, explain that and why in your answer. – MilkyTech Jun 05 '20 at 22:51
  • 1
    There can be more than one way to achieve the same effect, especially in creative coding. I don't see anything wrong with giving new answer to a six-year-old question. And rep shouldn't matter when judging the quality of an answer. – bytrangle Aug 12 '21 at 06:38