最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Reset canvas to previous picture after modifications - Stack Overflow

programmeradmin1浏览0评论

Say I have a simple canvas element, and draw a plicated, resource intensive picture on it. I then draw some simple lines on the picture. Would there be a way to "save" the state of the canvas (before the lines are drawn), and then redraw the state to erase any further changes made. I did try this with save() and restore() but I don't think the state for that includes the current shapes on the canvas. See my demo below.

var canvas = document.getElementById("canvas");
var context = canvas.getContext('2d');

function init() {
  // This is some putationally intensive drawing we don't want to repeat
  context.fillStyle = "rgb(150,29,28)";
  context.fillRect(40, 40, 255, 200);
  context.fillStyle = "rgb(150,83,28)";
  context.fillRect(10, 10, 50, 50);
  context.fillStyle = "rgb(17,90,90)";
  context.fillRect(5, 100, 200, 120);
  context.fillStyle = "rgb(22,120,22)";
  context.fillRect(200, 200, 90, 90);
  // Now we save the state so we can return to it
  saveState();
}

function lines() {
  // This is some drawing we will do and then want to get rid of
  context.beginPath();
  context.moveTo(125, 125);
  context.lineTo(150, 45);
  context.lineTo(200, 200);
  context.closePath();
  context.stroke();
}

function saveState() {
  //copy the data into some variable
}

function loadState() {
  //load the data from the variable and apply to canvas
}

init();
#canvas {
  border: 1px solid #000;
}
<canvas id="canvas" width="300" height="300"></canvas>
<button onClick="lines()">Draw over image</button>
<button onClick="loadState()">Restore</button>

Say I have a simple canvas element, and draw a plicated, resource intensive picture on it. I then draw some simple lines on the picture. Would there be a way to "save" the state of the canvas (before the lines are drawn), and then redraw the state to erase any further changes made. I did try this with save() and restore() but I don't think the state for that includes the current shapes on the canvas. See my demo below.

var canvas = document.getElementById("canvas");
var context = canvas.getContext('2d');

function init() {
  // This is some putationally intensive drawing we don't want to repeat
  context.fillStyle = "rgb(150,29,28)";
  context.fillRect(40, 40, 255, 200);
  context.fillStyle = "rgb(150,83,28)";
  context.fillRect(10, 10, 50, 50);
  context.fillStyle = "rgb(17,90,90)";
  context.fillRect(5, 100, 200, 120);
  context.fillStyle = "rgb(22,120,22)";
  context.fillRect(200, 200, 90, 90);
  // Now we save the state so we can return to it
  saveState();
}

function lines() {
  // This is some drawing we will do and then want to get rid of
  context.beginPath();
  context.moveTo(125, 125);
  context.lineTo(150, 45);
  context.lineTo(200, 200);
  context.closePath();
  context.stroke();
}

function saveState() {
  //copy the data into some variable
}

function loadState() {
  //load the data from the variable and apply to canvas
}

init();
#canvas {
  border: 1px solid #000;
}
<canvas id="canvas" width="300" height="300"></canvas>
<button onClick="lines()">Draw over image</button>
<button onClick="loadState()">Restore</button>

Share Improve this question asked Oct 13, 2016 at 17:50 James PatersonJames Paterson 2,9253 gold badges32 silver badges43 bronze badges 1
  • You would need to keep track of each state between as everything is merged to pixels (in place) on the canvas. Create a simple undo-redo stack (or try mine here: github./epistemex/undo-redo). – user1693593 Commented Oct 13, 2016 at 23:53
Add a ment  | 

2 Answers 2

Reset to default 7

You can easily just copy the canvas to a new one.

// canvas is the canvas you want to copy.
var canvasBack = document.createElement("canvas");
canvasBack.width = canvas.width;
canvasBack.height = canvas.height;
canvasBack.ctx = canvasBack.getContext("2d");
canvasBack.ctx.drawImage(canvas,0,0);

You treat the new canvas as if it is another image and can copy it to the original with

ctx.drawImage(canvasBack,0,0);

Rendering an image is done in hardware so can be done easily in realtime many times per frame. Because of this you can treat the canvases as layers (like photoshop) and using globalCompositeOperation create a wide range of adjustable FX.

You can convert to a dataURL but that is a much slower process and not quick enough for realtime rendering. Also keeping a copy of the DataURL string and then decoding it to an image will place a larger strain on memory than just creating a canvas copy (base64 encodes 3 bytes (24bit) in every 4 characters. As JS characters are 16 bits long storing data in base64 is very inefficient (64bits of memory used to store 24bits)

The an alternative is to store the canvas as a typed array with ctx.getImageData but this is also very slow, and can not handle realtime needs.

You can create an <img> element, call canvas.toDataURL() to store original canvas at saveState(), usecontext.clearRect()to clearcanvas,context.drawImage()to restore savedcanvas`

var canvas = document.getElementById("canvas");
var context = canvas.getContext('2d');
var _canvas;
var img = new Image;
img.width = canvas.width;
img.height = canvas.height;

function init() {
  // This is some putationally intensive drawing we don't want to repeat
  context.fillStyle = "rgb(150,29,28)";
  context.fillRect(40, 40, 255, 200);
  context.fillStyle = "rgb(150,83,28)";
  context.fillRect(10, 10, 50, 50);
  context.fillStyle = "rgb(17,90,90)";
  context.fillRect(5, 100, 200, 120);
  context.fillStyle = "rgb(22,120,22)";
  context.fillRect(200, 200, 90, 90);
  // Now we save the state so we can return to it
  saveState(canvas);
}

function lines() {
  // This is some drawing we will do and then want to get rid of
  context.beginPath();
  context.moveTo(125, 125);
  context.lineTo(150, 45);
  context.lineTo(200, 200);
  context.closePath();
  context.stroke();
}

function saveState(c) {
  _canvas = c.toDataURL();
  //copy the data into some variable
}

function loadState() {
  //load the data from the variable and apply to canvas
  context.clearRect(0, 0, canvas.width, canvas.height);
  img.onload = function() {
    context.drawImage(img, 0, 0);
  }
  img.src = _canvas;
}


init();
#canvas {
  border: 1px solid #000;
}
<canvas id="canvas" width="300" height="300"></canvas>
<button onClick="lines()">Draw over image</button>
<button onClick="loadState()">Restore</button>

发布评论

评论列表(0)

  1. 暂无评论