【问题标题】:Nesting setInterval function to successfully change canvas's context for multiple canvas animations嵌套 setInterval 函数以成功更改多个画布动画的画布上下文
【发布时间】:2014-09-12 15:43:59
【问题描述】:

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

我们将不胜感激任何反馈、cmets 和/或建议。

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);

应该可以在此处访问此演示 -> http://jsfiddle.net/justinbyrne001/TS8w7/

【问题讨论】:

    标签: javascript html animation canvas setinterval


    【解决方案1】:

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

    参考资料:

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

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

    不适用,(2010 年)。单个页面上的 HTML5 多个画​​布。 堆栈溢出堆栈交换。 取自:http://tinyurl.com/ll3o7vv

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

    尽管这篇原始帖子询问了如何嵌套 setInterval 函数以成功更改多个画布动画的画布上下文,但我能够通过将 stepStart 和 stepEnd 单个变量更改为数组来颠覆这一点。此外,我自然也改变了我原来的构造函数方法(如下所示),以反映(现在)存储在整个数组中的各种画布元素,同时包括要通过主构造函数传递的附加参数,包括 beginAnimation() 方法;甚至不需要 changeContext() 方法,更不用说嵌套的 setInterval 函数了。虽然,这种方法绝对有效,但我希望解决方案不会与最初的询问有太大的偏差。无论如何,我真诚地感谢您的反馈 ma​​rkE,并感谢您抽出宝贵的时间。下面的更新代码应该可以按预期工作,这里还有一个更新版本 (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);
    

    【讨论】:

      【解决方案2】:

      发出 .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 变量设置为任何所需的画布和上下文。

      function changeContext(num) {
          theCanvas = canvases[num];
          context = contexts[num];
      }
      

      顺便说一句,您可能希望使用单个画布而不是多个画布来测试您的代码。 Canvas 旨在快速有效地处理多组图纸。您可能会发现 1 个画布足够快,并且比多个画布占用的资源更少。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-07-25
        • 1970-01-01
        • 2016-04-29
        • 2015-07-18
        • 1970-01-01
        • 2015-08-05
        相关资源
        最近更新 更多