嵌套setInterval函数可成功更改多个画布动画的画布上下文

时间:2014-07-22 00:13:59

标签: javascript html5 animation canvas setinterval

这是我试图做的事情。到目前为止,我有2个画布元素,但我希望能够扩展它们(例如,添加更多)。在任何一种情况下,我目前在一个canvas元素中都能正常工作,但是,我想以迭代的方式从一个canvas元素切换到另一个(通过下面代码中的预构建的changeContext()函数)。我试图通过beginAnimation()函数触发一个动画,然后在完成之后,画布上下文被更改为下一个画布,而下一个实例化对象被推送到beginAnimation()功能。我有一种感觉,我可能必须通过嵌套setInterval和/或setTimeout函数来做到这一点,但是,我对这两种函数都不太擅长。

任何反馈,评论和/或建议肯定会受到赞赏。

window.addEventListener('load', eventWindowLoaded, false);

function eventWindowLoaded() { canvasApp(); }

function canvasSupport() { return Modernizr.canvas; }

function canvasApp() {

// if: no canvas support return, else declare 2D canvas
if (!canvasSupport()) { return; } else {
    var theCanvas = document.getElementById('cvs-1');
    var context = theCanvas.getContext('2d');
}

function changeContext(num) {
    theCanvas = document.getElementById('cvs-' + num);
    context = theCanvas.getContext('2d');
}

var stepStart = 0;
var stepEnd = 0.00;

// Constructor: myPercentage
var myPercentage = function(percentage) {
    this.strokeStyle = '#2B5981';                       // Blue
    this.lineWidth = 10;
    this.percentage = percentage;                       // Percentage
    this.degrees = this.percentage * 360.0;
    this.radians = this.degrees * (Math.PI / 180);
    this.x = 57.5;
    this.y = 57.5;
    this.r = 45;
    this.s = 1.5 * Math.PI;
    this.drawShape = function() {
        context.strokeStyle = this.strokeStyle;
        context.lineWidth = this.lineWidth;
        function clearCanvas(x,y,width,height) {
            context.rect(x,y,width,height);
            context.fillStyle = '#FCFCFC';
            context.fill();
        }
        function circle(x,y,r,startAngle,endAngle,counterClockwise) {
            context.beginPath();
            context.arc(x,y,r,startAngle,endAngle,counterClockwise);
            context.shadowColor = '#242424';
            context.shadowBlur = 7;
            context.stroke();
            context.closePath();
        }
        function writePercentage(percentage) {
            context.font = '20px Georgia';
            context.fillStyle = 'black';
            context.fillText(Math.round(percentage*100)+'%',40,62);
        }
        clearCanvas(0,0,115,115);
        this.degrees = this.percentage * 360.0;
        this.radians = this.degrees * (Math.PI / 180);
        circle(this.x,this.y,this.r,this.s,this.radians+this.s,false);
        writePercentage(this.percentage);
        context.save();
    };
};

function setSteps(object) {
    stepStart = 0;
    stepEnd = object.percentage * 100;
    object.percentage = 0.00;
}

//Instantiate: new percentages
var phpPerc = new myPercentage(0.75);
var jsPerc = new myPercentage(0.25);

function beginAnimation(object) {

    setSteps(object);

    setInterval(function() {
        if (stepStart < stepEnd) {
            object.percentage += 0.01;
            object.drawShape();
            stepStart++;
        } else {
            clearInterval();
        }
    }, 33);
}

beginAnimation(phpPerc);
// changeContext(2);
// beginAnimation(jsPerc);

此处的演示应该可以在这里访问 - &gt; http://jsfiddle.net/justinbyrne001/TS8w7/

2 个答案:

答案 0 :(得分:1)

制作像.getElementById这样的DOM请求相对昂贵。

最好是在应用程序开始时引用所有画布和上下文。

// get all canvas and context references once at the start of your app

var canvases=[];
canvases.push(document.getElementById('cvs-1'));
canvases.push(document.getElementById('cvs-2'));
canvases.push(document.getElementById('cvs-3'));

var contexts=[];
for(var i=0;i<canvases.length;i++){
    contexts.push(canvases[i].getContext('2d');
}

然后,您可以将theCanvascontext变量设置为任意所需的画布&amp;上下文。

function changeContext(num) {
    theCanvas = canvases[num];
    context = contexts[num];
}
BTW,您可能希望使用单个画布而不是多个画布来测试代码。 Canvas可以快速有效地处理多组图纸。您可能会发现1个画布足够快,占用的资源比多个画布少。

答案 1 :(得分:0)

好的,这绝对给了我完成这个小项目所需要的洞察力,我真诚地感谢它。但是,我对使用各种(或多个)画布会产生不必要的开销的整个概念感到有些困惑和冲突。我理解,并且非常感谢你提醒我关于在整个运行时间不断使用getElementById()函数的过程,这会(很可能)在动画期间产生不必要的开销。但是,我在各篇文章中都已经阅读过该元素已经作为DOM元素进行了优化,因此在使用多个画布或多个画布层时不需要进行后期制作优化。

<强>参考文献:

Ranfelt,A。,(2013)。使用分层优化HTML5画布渲染。 IBM developerWorks。      取自:http://tinyurl.com/m3yx682

N.A。,(2013)。使用多个画布对象是一个好习惯吗? 游戏开发堆栈      交换。取自:http://tinyurl.com/l4dlv6a

N.A。,(2010)。单页上的HTML5多个画布。 堆栈溢出堆栈交换。      取自:http://tinyurl.com/ll3o7vv

Litten,J。(2010)。使用多个HTML5画布作为图层。未知的卡达斯。      取自:http://tinyurl.com/6yspxzu

虽然,这篇原创帖子询问如何 Nest setInterval函数成功更改画布的多个画布动画的上下文,但我能够通过改变stepStart&amp; amp; stepEnd单个变量到数组。另外,我自然也改变了我的原始构造方法(如下所示),以反映整个数组中存储(现在)的各种canvas元素,同时包括要通过主构造函数传递的其他参数,包括beginAnimation()方法;否定甚至需要一个changeContext()方法,更不用说嵌套的setInterval函数了。虽然这种方法肯定有效,但我希望解决方案不会偏离原始查询过多。无论如何,我真诚地感谢您的反馈 markE ,并感谢您的时间。下面更新的代码应按预期工作,此处还有一个更新版本(http://jsfiddle.net/justinbyrne001/TS8w7/1/),以防有人想将它用于自己的项目。

// Declare: canvases array to store multiple canvas elements
var canvases=[];
    canvases.push(document.getElementById('cvs-1'));
    canvases.push(document.getElementById('cvs-2'));

// Declare: contexts array to store '2d' canvas API
var contexts=[];

// Store: '2d' canvas API throughout canvases array
for(var i=0; i<canvases.length; i++ ) {
    contexts.push(canvases[i].getContext('2d'));

}

// stepStart & stepEnd arrays
var stepStart=[];
var stepEnd=[];

// Constructor: myPercentage(percentage, context)
var myPercentage = function(percentage,ctx) {
    this.context = ctx;                                 // Context
    this.strokeStyle = '#2B5981';                       // Blue
    this.lineWidth = 10;
    this.percentage = percentage;                       // Percentage
    this.degrees = this.percentage * 360.0;
    this.radians = this.degrees * (Math.PI / 180);
    this.x = 57.5;
    this.y = 57.5;
    this.r = 45;
    this.s = 1.5 * Math.PI;
    this.drawShape = function() {
        contexts[ctx].strokeStyle = this.strokeStyle;
        contexts[ctx].lineWidth = this.lineWidth;
        function clearCanvas(x,y,width,height) {
            contexts[ctx].rect(x,y,width,height);
            contexts[ctx].fillStyle = '#FCFCFC';
            contexts[ctx].fill();
        }
        function circle(x,y,r,startAngle,endAngle,counterClockwise) {
            contexts[ctx].beginPath();
            contexts[ctx].arc(x,y,r,startAngle,endAngle,counterClockwise);
            contexts[ctx].shadowColor = '#242424';
            contexts[ctx].shadowBlur = 7;
            contexts[ctx].stroke();
            contexts[ctx].closePath();
        }
        function writePercentage(percentage) {
            contexts[ctx].font = '20px Georgia';
            contexts[ctx].fillStyle = 'black';
            contexts[ctx].fillText(Math.round(percentage*100)+'%',40,62);
        }
        clearCanvas(0,0,115,115);
        this.degrees = this.percentage * 360.0;
        this.radians = this.degrees * (Math.PI / 180);
        circle(this.x,this.y,this.r,this.s,this.radians+this.s,false);
        writePercentage(this.percentage);
        contexts[ctx].save();
    };
};

// Identify: number of steps to take between object's percentage
function setSteps(object) {
    stepStart[object.context] = 0;
    stepEnd[object.context] = object.percentage * 100;
    object.percentage = 0.00;
}

//Instantiate: new percentages
var onePerc = new myPercentage(0.90,0);
var twoPerc = new myPercentage(0.80,1);

// Initialize: animation with passed object
function beginAnimation(object) {

    setSteps(object);

    setInterval(function() {
        if (stepStart[object.context] < stepEnd[object.context]) {
            object.percentage += 0.01;
            object.drawShape();                         // Uncaught Reference
            stepStart[object.context]++;
        }
    }, 33);
}

// Call: animations to be executed
beginAnimation(onePerc,0);
beginAnimation(twoPerc,1);