Search code examples
html5-canvasfabricjsundo-redo

While implementing Undo Redo on fabric js the image disappears but appears on clicking on canvas area


I am working with a canvas and implementing undo-redo operation using JavaScript (Fabric.js). But the Undo Redo on Fabric.js the image disappears but appears on clicking on canvas area.

If anyone can provide any solution that would be helpful.

Running example : https://jsfiddle.net/devilla/wdrbohj5/4/

<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.5.0/fabric.min.js">
</script>
</head>

<body>
<div style=" height:80px; margin-bottom: 50px; margin-top: 50px;">
    <p style="width:30; height:15px;  font-size: 25px; font-family: appleberry;"></p>
    <img src="https://www.w3schools.com/css/trolltunga.jpg" onclick="clipFunction(this)" style="width:60px; height:35px;margin-left: 2px; margin-top: 2px; margin-right: 2px;margin-bottom: 2px;">
    <img src="https://www.planwallpaper.com/static/images/images_1_05GM1zY.jpg" onclick="clipFunction(this)" style="width:60px; height:35px;margin-left: 2px; margin-top: 2px; margin-right: 2px;margin-bottom: 2px;">
</div>
<div id="image5">
    <canvas id="c" height="500px" width="280px" style="position:fixed; border:0px solid lightblue; user-select: none; border-radius: 7px;">
    </canvas>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.5.0/fabric.min.js"></script>
    <script>
    var canvas = new fabric.Canvas('c');

    function clipFunction(elt) {



        fabric.Image.fromURL(elt.src, function(oImg) {
            oImg.setLeft(50);
            oImg.set({
                width: canvas.width / 2,
                height: canvas.height / 2
            });
            oImg.setTop(150);
            oImg.set('selectable', false);



            img = new fabric.Group([oImg]);
            canvas.add(img);

            canvas.renderAll();


        });

    }









    /* UNDO REDO   */


    var state = [];
    var mods = 0;
    canvas.on(
        'object:modified',
        function() {
            updateModifications(true);
        },
        'object:added',
        function() {
            updateModifications(true);
        });

    function updateModifications(savehistory) {
        if (savehistory === true) {
            myjson = JSON.stringify(canvas);
            state.push(myjson);
        }
    }

    undo = function undo() {
        if (mods < state.length) {
            canvas.clear().renderAll();
            canvas.loadFromJSON(state[state.length - 1 - mods - 1]);
            canvas.renderAll();
            //console.log("geladen " + (state.length-1-mods-1));
            //console.log("state " + state.length);
            mods += 1;
            //console.log("mods " + mods);
        }
    }

    redo = function redo() {
        if (mods > 0) {
            canvas.clear().renderAll();
            canvas.loadFromJSON(state[state.length - 1 - mods + 1]);
            canvas.renderAll();
            //console.log("geladen " + (state.length-1-mods+1));
            mods -= 1;
            //console.log("state " + state.length);
            //console.log("mods " + mods);
        }
    }

    clearcan = function clearcan() {
            canvas.clear().renderAll();

        }
        /**/
    </script>
</div>
<div id="UR" style="position: fixed; bottom :10px; height:50px;width:180px; border:1px solid lightgreen;">
    <input type="button" value="undo" onclick="undo()">
    <input type="button" value="redo" onclick="redo()">
    <input type="button" value="clear" onclick="clearcan()">
</div>


Solution

  • This happens because loadFromJSON is async.

    you cannot call

    canvas.loadFromJSON(json) canvas.renderAll()

    but you should use

    canvas.loadFromJSON(json, function() { canvas.renderAll() })