क्या HTML5 / कैनवास डबल बफरिंग का समर्थन करता है?


83

जो मैं करना चाहता हूं वह मेरे ग्राफिक्स को एक बफर पर खींचता है और फिर इसे कॉपी करने में सक्षम होता है जैसा कि कैनवास पर है, इसलिए मैं एनीमेशन कर सकता हूं और झिलमिलाहट से बच सकता हूं। लेकिन मुझे यह विकल्प नहीं मिला। किसी को पता है कि मैं इस बारे में कैसे जा सकता हूं?


12
मेरा अनुभव यह रहा है कि कैनवास ड्राइंग को ब्राउजर द्वारा coalesced किया जाता है ताकि एनिमेशन सहज हों। क्या आप कुछ कोड साझा कर सकते हैं जो आपके वर्णन के अनुसार फ़्लिकर करते हैं?
आंखों की रोशनी

2
मैंने देखा है कि IE का उपयोग करते समय कुछ मामलों में झिलमिलाहट हो सकती है explorercanvas, लेकिन यह एचटीएमएल 5 नहीं है और canvasकेवल वीएमएल द्वारा अनुकरण किया गया एक तत्व है। मैंने कभी भी किसी अन्य ब्राउज़र को ऐसा करते नहीं देखा।
क्रायो

3
से संबंधित है stackoverflow.com/questions/11777483
julien

2
वास्तव में गूंगा शुरुआत कोड कि झिलमिलाहट नहीं करता है। jsfiddle.net/linuxlizard/ksohjr4f/3 सभी अधिकारों के अनुसार, टिमटिमाना चाहिए। ब्राउज़र प्रभावशाली हैं।
डेविड पोले

यदि आपके पास एक async ड्रा फ़ंक्शन है तो आपको केवल डबल बफरिंग की आवश्यकता है। जब तक आप ब्राउज़र को उपज नहीं देते हैं, तब तक ड्राइंग को समकालिक बनाएं। आप ठीक रहेंगे। जैसे ही आप कोई वादा या सेटटाइमआउट या वहां कुछ जोड़ते हैं, आप ब्राउज़र पर वापस आ जाते हैं और यह वर्तमान स्थिति को आकर्षित करेगा, इससे पहले कि यह प्रभावी रूप से झिलमिलाहट पैदा करे।
अल्बर्टजन

जवाबों:


38

निम्न सहायक लिंक, डबल बफ़रिंग का उपयोग करने के उदाहरण और फायदे दिखाने के अलावा, html5 कैनवास तत्व का उपयोग करने के लिए कई अन्य प्रदर्शन युक्तियां दिखाता है। इसमें jsPerf परीक्षण के लिंक शामिल हैं, जो ब्राउज़रों के परीक्षण के परिणाम को एक ब्राउजरस्कोप डेटाबेस में एकत्रित करते हैं। यह सुनिश्चित करता है कि प्रदर्शन युक्तियां सत्यापित हैं।

http://www.html5rocks.com/en/tutorials/canvas/performance/

आपकी सुविधा के लिए, मैंने लेख में वर्णित प्रभावी डबल बफरिंग का एक न्यूनतम उदाहरण शामिल किया है।

// canvas element in DOM
var canvas1 = document.getElementById('canvas1');
var context1 = canvas1.getContext('2d');

// buffer canvas
var canvas2 = document.createElement('canvas');
canvas2.width = 150;
canvas2.height = 150;
var context2 = canvas2.getContext('2d');

// create something on the canvas
context2.beginPath();
context2.moveTo(10,10);
context2.lineTo(10,30);
context2.stroke();

//render the buffered canvas onto the original canvas element
context1.drawImage(canvas2, 0, 0);

83

एक बहुत ही सरल तरीका है कि एक ही स्क्रीन लोकेशन पर दो कैनवस-एलिमेंट्स हों और बफर के लिए विजिबिलिटी सेट करें जिसे आपको दिखाना है। जब आप कर रहे हों तो छिपे हुए पर पलटें और पलटें।

कुछ कोड:

सीएसएस:

canvas { border: 2px solid #000; position:absolute; top:0;left:0; 
visibility: hidden; }

JS में फ़्लिप करना:

Buffers[1-DrawingBuffer].style.visibility='hidden';
Buffers[DrawingBuffer].style.visibility='visible';

DrawingBuffer=1-DrawingBuffer;

इस कोड में सरणी 'बफ़र्स [] दोनों कैनवास-ऑब्जेक्ट्स रखती है। इसलिए जब आप ड्राइंग शुरू करना चाहते हैं तब भी आपको संदर्भ प्राप्त करने की आवश्यकता होती है:

var context = Buffers[DrawingBuffer].getContext('2d');

विषय से बाहर: मैं व्यक्तिगत रूप <noscript>से जावास्क्रिप्ट में अपने कैनवास तत्वों का उपयोग करना और बनाना पसंद करता हूं। आप आम तौर पर जावास्क्रिप्ट के लिए किसी भी तरह कैनवास समर्थन की जांच करना चाहते हैं, तो आप अपने HTML में एक कैनवास फालबैक संदेश क्यों डालना चाहेंगे?
शीया

19

मैंने जिन ब्राउज़रों का परीक्षण किया है, वे सभी को इस कैनवास के पुनरावृत्ति से रोकते हैं, जब तक कि कोड आपके फ्रेम को पूरा नहीं करता है। WHATWG मेलिंग सूची भी देखें: http://www.mail-archive.com/whatwg@lists.whatwg.org/msg19969.html


10
खैर मैं एक झिलमिलाहट या स्क्रीन आंसू नोटिस। निश्चित नहीं कि इसका वर्णन कैसे किया जाए। लिनक्स पर नवीनतम क्रोम का उपयोग करना।
ग्रोम जूल

14

आप हमेशा ऐसा कर सकते हैं var canvas2 = document.createElement("canvas"); और इसे DOM पर बिल्कुल नहीं जोड़ सकते।

आप लोग कह रहे हैं कि आप display:none; इसके साथ इतने आसक्त लग रहे हैं कि बस मुझे साफ-सुथरा लगता है और एक अजीब अदृश्य कैनवास होने की तुलना में डबल बफ़रिंग तरीके के विचार की नकल करता है।


8

दो साल से अधिक समय बाद:

दोहरे बफ़रिंग को 'मैन्युअल रूप से लागू करने' की कोई आवश्यकता नहीं है। मिस्टर गेरी ने इस बारे में अपनी पुस्तक "एचटीएमएल 5 कैनवस" में लिखा है ।

प्रभावी ढंग से झिलमिलाहट का उपयोग कम करने के लिए requestAnimationFrame()!


1
आप डबल बफ़रिंग का उपयोग करके देखे गए प्रदर्शन सुधारों की व्याख्या कैसे करते हैं? html5rocks.com/en/tutorials/canvas/performance
रिक

@ricksuggs खैर, html5rocks पर उल्लिखित "डबल बफरिंग" या "ऑफस्क्रीन-रेंडरिंग" थोड़ा अलग है, जितना मैंने सोचा था। मैंने DB को स्क्रीन पेज स्वैप करने के रूप में माना (vram में), जो प्रभावी रूप से मेमोरी चंक्स कॉपी करने के बजाय केवल एक पॉइंटर ऑपरेशन था। ओपी ने टिमटिमा से बचने के लिए DB का उपयोग करने के लिए कहा, जो वास्तव में requestAnimationFrame () द्वारा संबोधित किया गया है। हो सकता है कि ऑफस्क्रीन-रेंडरिंग के बारे में यह लेख दिलचस्प हो। वहाँ मैं एक बफर बफर का उपयोग कर स्क्रीन पर बफ़र छवि डेटा की प्रतिलिपि बनाने और चिपकाने के बारे में ओपी के प्रश्न का उत्तर देता हूं
ohager

6

जोश ने (थोड़ी देर पहले) पूछा कि ब्राउज़र कैसे जानता है "जब ड्राइंग प्रक्रिया समाप्त हो जाती है" तो झिलमिलाहट से बचने के लिए। मैंने उनकी पोस्ट पर सीधे टिप्पणी की होगी, लेकिन मेरा प्रतिनिधि उच्च नहीं है। साथ ही यह सिर्फ मेरी राय है। मेरे पास इसे वापस करने के लिए तथ्य नहीं हैं, लेकिन मैं इसके बारे में काफी आश्वस्त महसूस करता हूं और भविष्य में इसे पढ़ने वाले अन्य लोगों के लिए यह उपयोगी हो सकता है।

मैं अनुमान लगा रहा हूं कि जब आप ड्राइंग कर रहे हैं तो ब्राउज़र को "पता नहीं" है। लेकिन अधिकांश जावास्क्रिप्ट की तरह, जब तक आपका कोड ब्राउज़र पर नियंत्रण के बिना चलता है, तब तक ब्राउज़र अनिवार्य रूप से लॉक हो जाता है और अपने UI पर अपडेट / प्रतिक्रिया नहीं दे सकता है। मैं अनुमान लगा रहा हूं कि यदि आप कैनवास को साफ करते हैं और ब्राउज़र पर नियंत्रण के बिना अपने पूरे फ्रेम को खींचते हैं, तो यह वास्तव में आपके कैनवास को तब तक नहीं खींचेगा जब तक आप इसे पूरा नहीं कर लेते।

यदि आप एक ऐसी स्थिति सेट करते हैं, जहाँ आपका रेंडर कई सेटटाइमआउट / सेट इन्टरवल / रिक्वेस्ट एनाइमेशनफ्रेम कॉल करता है, जहाँ आप एक कॉल में कैनवस को क्लियर करते हैं और अगले कई कॉल्स में अपने कैनवस पर एलिमेंट ड्रॉ करते हैं, तो हर 5 कॉल में साइकिल (उदाहरण के लिए) को दोहराते हैं प्रत्येक शर्त के बाद कैनवास अपडेट होने के बाद आप फ़्लिकर देखना चाहते हैं।

उस ने कहा, मुझे यकीन नहीं है कि मुझे भरोसा होगा। हम पहले से ही इस बिंदु पर हैं कि जावास्क्रिप्ट को निष्पादन से पहले देशी मशीन कोड में संकलित किया जाता है (कम से कम यही क्रोम का V8 इंजन जो मुझे समझ में आता है)। मुझे आश्चर्य नहीं होगा कि यह बहुत पहले नहीं था जब ब्राउज़र ने UI से एक अलग थ्रेड में अपनी जावास्क्रिप्ट को चलाना शुरू कर दिया था और किसी भी यूआई तत्वों को यूआई को अपडेट करने / प्रतिक्रिया करने के लिए यूआई को अपडेट करने की अनुमति देने वाले यूआई तत्वों को सिंक्रोनाइज़ करना शुरू कर दिया था। जब / अगर ऐसा होता है (और मैं समझता हूं कि कई बाधाएं हैं, जिन्हें दूर करना होगा, जैसे कि घटना संचालकों को किक मारते हुए जब आप अभी भी अन्य कोड चला रहे हैं), तो हम शायद कैनवास एनीमेशन पर झिलमिलाहट देखेंगे जो उपयोग नहीं कर रहे हैं किसी तरह का दोहरापन।

व्यक्तिगत रूप से, मुझे दो कैनवस तत्वों के विचार एक दूसरे के ऊपर तैनात हैं और बारी-बारी से जो प्रत्येक फ्रेम पर दिखाए / खींचे गए हैं। कोड की कुछ पंक्तियों के साथ एक मौजूदा अनुप्रयोग में बहुत आसानी से अनपेक्षित और शायद बहुत आसानी से जोड़ा गया।


बिल्कुल सही। एक उदाहरण के लिए JSFiddle को यहां देखें stackoverflow.com/questions/11777483/…
एरिक

6

अविश्वासियों के लिए, यहाँ कुछ चंचल कोड है। ध्यान दें कि मैं पिछले सर्कल को मिटाने के लिए स्पष्ट रूप से स्पष्ट कर रहा हूं।

var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");

function draw_ball(ball) {
    ctx.clearRect(0, 0, 400, 400);
    ctx.fillStyle = "#FF0000";
    ctx.beginPath();
    ctx.arc(ball.x, ball.y, 30, 0, Math.PI * 2, true);
    ctx.closePath();
    ctx.fill();
}

var deltat = 1;
var ball = {};
ball.y = 0;
ball.x = 200;
ball.vy = 0;
ball.vx = 10;
ball.ay = 9.8;
ball.ax = 0.1;

function compute_position() {
    if (ball.y > 370 && ball.vy > 0) {
        ball.vy = -ball.vy * 84 / 86;
    }
    if (ball.x < 30) {
        ball.vx = -ball.vx;
        ball.ax = -ball.ax;
    } else if (ball.x > 370) {
        ball.vx = -ball.vx;
        ball.ax = -ball.ax;
    }
    ball.ax = ball.ax / 2;
    ball.vx = ball.vx * 185 / 186;
    ball.y = ball.y + ball.vy * deltat + ball.ay * deltat * deltat / 2
    ball.x = ball.x + ball.vx * deltat + ball.ax * deltat * deltat / 2
    ball.vy = ball.vy + ball.ay * deltat
    ball.vx = ball.vx + ball.ax * deltat
    draw_ball(ball);
}

setInterval(compute_position, 40);
<!DOCTYPE html>
<html>
<head><title>Basketball</title></head>
<body>
<canvas id="myCanvas" width="400" height="400" style="border:1px solid #c3c3c3;">
Your browser does not support the canvas element.
</canvas>
</body></html>


4
मेरे लिए झिलमिलाहट नहीं लगती है, कम से कम तब नहीं जब गेंद अपने दायरे से अधिक हर फ्रेम से आगे नहीं बढ़ रही हो। क्रोम / विंडोज।
जूल्स

10
मैंने रिक्वेस्ट में एक कॉल जोड़ा है AimimFrame - यहाँ देखें - अपने उदाहरण के लिए jsfiddle.net/GzSWJ/28 पर - यह किसी भी तरह से नहीं झिलमिलाता है
rhu

5

वेब ब्राउज़रों में कोई टिमटिमा नहीं है! वे पहले से ही अपने प्रतिपादन के लिए dbl बफरिंग का उपयोग करते हैं। Js इंजन आपके सभी रेंडर को दिखाने से पहले बना देगा। इसके अलावा, संदर्भ केवल स्टैक परिवर्तनकारी मैट्रिक्स डेटा को बचाने और पुनर्स्थापित करने के लिए और, कैनवास सामग्री को ही नहीं। तो, आप की जरूरत नहीं है या dbl बफरिंग चाहते हैं!


8
क्या आप अपने दावों का समर्थन करने के लिए कुछ सबूत दे सकते हैं?
रिक सूग्स

@ricksuggs मैं एनिमेशन में बुरे झटके में DB परिणामों का उपयोग नहीं कर रहा हूँ, मैंने अभी तक DB की कोशिश नहीं की है
FutuToad

3

अपना खुद का रोल करने के बजाय, आप संभवतः एक मौजूदा लाइब्रेरी का उपयोग करके स्वच्छ और झिलमिलाहट मुक्त जावास्क्रिप्ट बनाने के लिए सबसे अच्छा लाभ प्राप्त करने जा रहे हैं:

यहाँ एक लोकप्रिय है: http://processingjs.org


94
बिल्कुल सही! क्यों परेशान करें और अपने स्वयं के कोड की 10 पंक्तियाँ लिखें, जब आप केवल थोड़ी सी भी सुराग के बिना पूरे 275KB पुस्तकालय का उपयोग कर सकते हैं !? हाँ, मैं व्यंग्यात्मक हो रहा था।
टॉम

10
येश, बहुत कठोर?
davidtbernal

3

आपको 2 कैनवस चाहिए: (सीएसएस जेड-इंडेक्स और स्थिति पर ध्यान दें: निरपेक्ष)

<canvas id="layer1" width="760" height="600" style=" position:absolute; top:0;left:0; 
visibility: visible;  z-index: 0; solid #c3c3c3;">
Your browser does not support the canvas element.
</canvas>
<canvas id="layer2" width="760" height="600" style="position:absolute; top:0;left:0; 
visibility: visible;  z-index: 1; solid #c3c3c3;">
Your browser does not support the canvas element.
</canvas>

आप देख सकते हैं कि पहला कैनवास दिखाई दे रहा है और दूसरा यह विचार छिपा हुआ है कि वह छिपे हुए पर आकर्षित होगा उसके बाद हम दृश्य को छिपाएंगे और छिपे हुए कैनवास को दृश्यमान बनाएंगे। जब यह छिपा हुआ है 'स्पष्ट छिपा हुआ कैनवास

<script type="text/javascript">
var buff=new Array(2);
buff[0]=document.getElementById("layer1");
buff[1]=document.getElementById("layer2");

ctx[0]=buff[0].getContext("2d");
ctx[1]=buff[1].getContext("2d");
var current=0;
// draw the canvas (ctx[ current ]);
buff[1- current ].style.visibility='hidden';
buff[ current ].style.visibility='visible';
ctx[1-current].clearRect(0,0,760,600);
current =1-current;

अच्छा कार्यान्वयन, उस स्थिति में जब किसी को मैन्युअल रूप से डबल बफरिंग तकनीक को लागू करने की आवश्यकता होती है। बस निम्नलिखित पंक्ति जोड़ें: var ctx = new Array (2); ऊपर अपने कोड में खाली लाइन के लिए।
डिमैट

2

ओपेरा 9.10 बहुत धीमा है और ड्राइंग प्रक्रिया को दर्शाता है। यदि आप किसी ब्राउज़र को डबल बफरिंग का उपयोग नहीं करना चाहते हैं, तो ओपेरा को 9.10 से आज़माएं।

कुछ लोगों ने सुझाव दिया कि ब्राउजर किसी तरह निर्धारित कर रहे हैं कि ड्राइंग प्रक्रिया कब समाप्त होगी लेकिन क्या आप बता सकते हैं कि यह कैसे काम कर सकता है? मैंने फ़ायरफ़ॉक्स, क्रोम, या IE9 में किसी भी स्पष्ट झिलमिलाहट पर ध्यान नहीं दिया है, यहां तक ​​कि जब ड्राइंग धीमा है, तो ऐसा लगता है कि जैसा वे कर रहे हैं, लेकिन जो पूरा किया गया है वह मेरे लिए एक रहस्य है। ब्राउज़र को कभी कैसे पता चलेगा कि यह अधिक ड्राइंग निर्देशों को निष्पादित करने से ठीक पहले प्रदर्शन को ताज़ा कर रहा है? क्या आपको लगता है कि वे इसे सिर्फ इतना समय देते हैं यदि 5 से अधिक का अंतराल या एक कैनवास ड्राइंग निर्देश को निष्पादित किए बिना जाता है, यह मानता है कि यह सुरक्षित रूप से बफ़र्स को स्वैप कर सकता है?


2

ज्यादातर स्थितियों में, आपको ऐसा करने की आवश्यकता नहीं है, ब्राउज़र आपके लिए इसे लागू करता है। लेकिन हमेशा उपयोगी नहीं!

आपके ड्राइंग बहुत जटिल होने पर भी आपको इसे लागू करना होगा। अधिकांश स्क्रीन अपडेट दर 60Hz के बारे में है, इसका मतलब है कि स्क्रीन अपडेट प्रति 16ms। इस नंबर के पास ब्राउज़र की अपडेट दर हो सकती है। यदि आपके आकार को पूरा करने के लिए 100ms की आवश्यकता है, तो आपको एक अपूर्ण आकार दिखाई देगा। तो आप इस स्थिति में डबल बफरिंग लागू कर सकते हैं।

मैंने एक परीक्षण किया है: Clear a rect, wait for some time, then fill with some color.अगर मैं 10ms तक का समय निर्धारित करता हूं, तो मैं झिलमिलाहट नहीं देखूंगा। लेकिन अगर मैं इसे 20ms पर सेट करता हूं, तो टिमटिमा होता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.