在对象中缓存画布(在内存中)

时间:2015-11-02 17:06:35

标签: javascript jquery object canvas clone

我正在尝试缓存用户为画布设置的不同状态,

事情是,当我稍后追加它时使用.pushcanvas.clone()它的大小相同,但是白色;没有它显示的图像,

canvas存储在内存中的任何有效方法都可用吗?

- 编辑 -

这就是我尝试

的方式
effectosFotos: function ($foto) {
        var t;
        var selector = '#'+$foto.attr('id');
        var $foto = $(selector);
        var $backup = $foto.clone();
        var times = 0;
        var cached = [];

        $('.filters').show();

    var img1 = document.createElement('img');
    img1.onload = function () {
        var width1 = $('.filters li').eq(0).width()/3;
        var height1 = this.height*(width1/this.width);

        console.log(width1, height1);

        var canvas1 = document.createElement('canvas'),
                ctx1 = canvas1.getContext('2d');
        canvas1.width = width1;
        canvas1.height = height1;

            ctx1.drawImage(this, 0, 0, width1, height1);
        var newUrl = canvas1.toDataURL('image/jpeg', 0.8);
        $('.filters li a').each(function() {
                $(this).append( '<img id="preview_'+$(this).data('id')+'" src="'+newUrl+'">'  );  
        });



        $('.filters li a').each(function(i) {
                var $this = $(this);
                t = setTimeout(function () {
                    var effect = $this.data('id');
                    var $img = $('#preview_'+effect);
                    //console.log('Item='+i +' About to render '+ effect +' and exists? ' + $img.length );
                    Caman('#preview_'+effect, function () {
                        this[effect]();
                        this.render(function(){
                                 //console.log('rendered '+effect);
                                 $this.parent().addClass('rendered');
                        });
                    }); 

                }, 1*i)


        });
    }
        img1.src = $foto.attr('src');       

        $('.filters').on('click', 'li:not(.active) a', function(e){
            var start = new Date().getTime();
            var $this = $(this).addClass('loading');
            $this.parent().addClass('loading');


            e.preventDefault();
            var effect = $(this).data('id');
            var parent = $(selector).parent();
            //console.log('f'+$(selector).length, effect,times,$(selector).prop("tagName"),$backup.prop("tagName"));
            /*if(times == 0){
                    $backup = $foto.clone();
            }
            times++;*/
            $(selector).remove();
            parent.append($backup);
            console.log(cached);

            var found = -1;
            for ( var c = 0; c < cached.length; c++ ) {
                var item = cached[c];
                if ( item.effect == effect ) {
                    found = c;
                } 
            }
            if (effect == 'normal'){
                $(selector).css('opacity',1);
                $this.parent().addClass('active').removeClass('loading').siblings().removeClass('active');
            } else if ( found > -1 ) {



            console.log('Cargamos caché  ' + effect + ' a '+width +'x'+height);
            var canvas = document.getElementById($foto.attr('id'))
            canvas.width = width;
            canvas.height = height;
            var ctx3 = canvas.getContext('2d');
            ctx3.clearRect(  0, 0, width, height );
            ctx3.drawImage( cached[found].canvas, 0, 0);
            $this.parent().addClass('active').removeClass('loading').siblings().removeClass('active');
      } else  {
            $(selector).remove();
            parent.append($backup);
            $(selector).css('opacity',0.3); 
            $('.takePictureHolder').addClass('caming');
            Caman(selector, function () {
                this[effect]();
                this.render(function(){
                    $(selector).css('opacity',1);  
                    $this.parent().addClass('active').removeClass('loading').siblings().removeClass('active');
                    $('.takePictureHolder').removeClass('caming');
                    if (found == -1) {
                        var canvas = document.getElementById($foto.attr('id'));
                        var clone = canvas.cloneNode(true);
                           clone.getContext('2d').drawImage(canvas, 0,0);
                        cached.push({ 'effect' :effect, "canvas":clone });
                        /*var ctx4 = document.getElementById($foto.attr('id')).getContext('2d');
                        console.log('Cacheamos ' + effect + ' a '+width +'x'+height);
                        cached.push({ 'effect' :effect, "canvas":ctx4.getImageData(0,0,width, height) });*/
                    }
                    var end = new Date().getTime();
                    var time = end - start;
                    console.log('Execution time: ' + time);
                }); 
            });         
        }       
        });
    }

2 个答案:

答案 0 :(得分:2)

您可以使用.getImageData()保存画布的内容 并.putImageData()用于恢复旧内容。

null

var data = [];

// store canvas/image
data.push(context.getImageData(0, 0, canvas.width, canvas.height));


// restore canvas/image
var oldData = data.pop();

canvas.width = oldData.width;
canvas.height = oldData.height;
context.clearRect(oldData, 0, 0, canvas.width, canvas.height);
context.putImageData(oldData, 0, 0);
var canvas = document.querySelector("canvas"),
    context = canvas.getContext("2d"),
    states = [],
    img;

console.log("setup states...");
setupState();


function rndColor() {
    var rgb = [];
    
    for (var i = 0; i < 3; i++) {
        rgb.push(Math.floor(Math.random() * 255));
    }
    
    return "rgb(" + rgb.join(",") + ")";
}

function setupState() {
    canvas.width = 50 + Math.floor(Math.random() * 100);
    canvas.height = 50 + Math.floor(Math.random() * 100);
    context.fillStyle = rndColor();
    context.fillRect(0, 0, canvas.width, canvas.height);

    states.push(context.getImageData(0, 0, canvas.width, canvas.height));

    if (states.length < 5) {
        setTimeout(setupState, 1000);
    } else {
        console.log("restore states...");
    	setTimeout(restoreStates, 2000);
    }
}

function restoreStates() {
    var state = states.shift();
    
    canvas.width = state.width;
    canvas.height = state.height;
    
    context.clearRect(0, 0, state.width, state.height);
    context.putImageData(state, 0, 0);
    
    if (states.length) {
        setTimeout(restoreStates, 1000);
    }
}
canvas { border: solid 5px blue }

.toDataUrl()可以实现同样的目标 和.drawImage()
但这将是较慢的方法:jsperf(至少在chrome中)

<canvas></canvas>

var images = [];

// store canvas/image
var img = new Image();
img.src = canvas.toDataURL();
images.push(img);


// restore canvas/image
var oldImage = images.pop();

canvas.width = oldImage.width;
canvas.height = oldImage.height;
context.clearRect(0, 0, canvas.width, canvas.height);
context.drawImage(oldImage, 0, 0);
var canvas = document.querySelector("canvas"),
    context = canvas.getContext("2d"),
    states = [],
    img;

console.log("setup states...");
setupState();


function rndColor() {
    var rgb = [];
    
    for (var i = 0; i < 3; i++) {
        rgb.push(Math.floor(Math.random() * 255));
    }
    
    return "rgb(" + rgb.join(",") + ")";
}

function setupState() {
    canvas.width = 50 + Math.floor(Math.random() * 100);
    canvas.height = 50 + Math.floor(Math.random() * 100);
    context.fillStyle = rndColor();
    context.fillRect(0, 0, canvas.width, canvas.height);

    img = new Image();
    img.src = canvas.toDataURL();
    states.push(img);

    if (states.length < 5) {
        setTimeout(setupState, 1000);
    } else {
        console.log("restore states...");
    	setTimeout(restoreStates, 2000);
    }
}

function restoreStates() {
    var state = states.shift();
    
    canvas.width = state.width;
    canvas.height = state.height;
    
    context.clearRect(0, 0, canvas.width, canvas.height);
    context.drawImage(state, 0, 0);
    
    if (states.length) {
        setTimeout(restoreStates, 1000);
    }
}
canvas { border: solid 5px blue }

答案 1 :(得分:2)

比导出方法更简单,更有效的方法是使用clonedCtx.drawImage(canvas, 0,0)在克隆上绘制待保存的画布。然后,您将能够将克隆的画布存储在数组中:

安德烈亚斯&#39;已修改代码的代码段:

&#13;
&#13;
var canvas = document.querySelector("canvas"),
    context = canvas.getContext("2d"),
    states = [];

console.log('setup states...');
setupState();


function rndColor() {
    var rgb = [];
    
    for (var i = 0; i < 3; i++) {
        rgb.push(Math.floor(Math.random() * 255));
    }
    
    return "rgb(" + rgb.join(",") + ")";
}

function setupState() {
    canvas.width = 50 + Math.floor(Math.random() * 100);
    canvas.height = 50 + Math.floor(Math.random() * 100);
    context.fillStyle = rndColor();
    context.fillRect(0, 0, canvas.width, canvas.height);

    var clone = canvas.cloneNode(true);
    clone.getContext('2d').drawImage(canvas, 0,0);
    states.push(clone)

    if (states.length < 5) {
        setTimeout(setupState, 1000);
    } else {
        console.log("restore states...");
    	setTimeout(restoreStates, 2000);
    }
}

function restoreStates() {
    var state = states.shift();
    
    canvas.width = state.width;
    canvas.height = state.height;
    
    context.clearRect(0, 0, state.width, state.height);
    context.drawImage(state, 0, 0);
    
    if (states.length) {
        setTimeout(restoreStates, 1000);
    }
}
&#13;
canvas { border: solid 5px blue }
&#13;
<canvas></canvas>
&#13;
&#13;
&#13;

但是,正如@markE所指出的,如果您需要存储很多这些状态(例如,如果您想要实现撤消/重做功能),它可以快速填满您的所有记忆。

然后推荐的方法是保存所有绘图操作并重新应用它们。还在使用Andreas&#39;片段,最小的实现可能是:

&#13;
&#13;
var canvas = document.querySelector("canvas"),
    context = canvas.getContext("2d"),
    states = [];

console.log('setup states...');
setupState();


function rndColor() {
    var rgb = [];
    
    for (var i = 0; i < 3; i++) {
        rgb.push(Math.floor(Math.random() * 255));
    }
    
    return "rgb(" + rgb.join(",") + ")";
}

function setupState() {
    // create an object with all our states settings and operations
    var state = {fillStyle: rndColor(), width: Math.floor(Math.random() * 100), height:Math.floor(Math.random() * 100)};
    // save the operations in an array
    state.operations = [{name:'fillRect',arguments: [0,0,state.width, state.height]}];
    // save the state
    states.push(state);
    // parse it a first time;
    parse(state);
  
    if (states.length < 5) {
        setTimeout(setupState, 1000);
    } else {
        console.log("restore states...");
    	setTimeout(restoreStates, 2000);
    }
}

function parse(state){
    // restore our canvas and context's properties
    // this could be improved by creating canvas and context objects in our state and then restore the corresponding with a for(x in y) loop
    canvas.width = state.width;
    canvas.height = state.height;
    context.fillStyle = state.fillStyle;
    // retrieve the operations we applied
    var op = state.operations;
    // loop through them
    for(var i=0; i<op.length; i++){
      // check it actually exists as a function
      if(typeof context[op[i].name]==='function')
        // apply the saved arguments
        context[op[i].name].apply(context, op[i].arguments);
      }
  }

function restoreStates() {
    var state = states.shift();
    parse(state);
    if (states.length) {
        setTimeout(restoreStates, 1000);
    }
}
&#13;
canvas { border: solid 1px blue }
&#13;
<canvas></canvas>
&#13;
&#13;
&#13;