कई सालों से, वेब डेवलपर को वेब पर जटिल और ज़्यादा इंटरैक्टिव विज़ुअल ऐप्लिकेशन बनाते समय, आर्किटेक्चर से जुड़ा मुश्किल फ़ैसला लेना पड़ता है. क्या आपको बेहतर सिमैंटिक सुविधाओं के लिए, DOM पर भरोसा करना चाहिए या ग्राफ़िक्स की परफ़ॉर्मेंस को बेहतर बनाने के लिए, सीधे <canvas> एलिमेंट पर रेंडर करना चाहिए?
एक्सपेरिमेंट के तौर पर उपलब्ध नए HTML-in-Canvas API का इस्तेमाल करके, आपको किसी एक को चुनने की ज़रूरत नहीं है. यह ऑरिजिन ट्रायल में उपलब्ध है. इस एपीआई की मदद से, सीधे तौर पर DOM कॉन्टेंट को 2D कैनवस या WebGL/WebGPU टेक्सचर में बनाया जा सकता है. साथ ही, यूज़र इंटरफ़ेस (यूआई) को इंटरैक्टिव, ऐक्सेस किया जा सकने वाला, और अपने पसंदीदा ब्राउज़र की सुविधाओं से जोड़ा जा सकता है. एचटीएमएल को लो-लेवल ग्राफ़िक्स प्रोसेसिंग के साथ मिलाकर, ऐसे अनुभव बनाए जा सकते हैं जो पहले मुमकिन नहीं थे.
DOM बनाम कैनवस
इस नए एपीआई की अहमियत को समझने के लिए, DOM और Canvas, दोनों की तुलना करना ज़रूरी है.
डीओएम, वेब यूज़र इंटरफ़ेस (यूआई) का मुख्य हिस्सा होता है. यह टेक्स्ट लेआउट के लिए, बॉक्स से बाहर के समाधान उपलब्ध कराता है. साथ ही, यह रिच इंटरफ़ेस बनाने के लिए, सिमैंटिक तौर पर समझे गए कॉन्टेंट का इस्तेमाल करता है. इससे उपयोगकर्ता, वेब पेजों पर सामान्य कार्रवाइयां आसानी से कर पाते हैं. जैसे, कॉपी करने के लिए टेक्स्ट को हाइलाइट करना या इमेज को सेव करने के लिए उस पर राइट क्लिक करना. DOM, ब्राउज़र की ज़रूरी सुविधाओं के साथ भी इंटिग्रेट होता है: सुलभता टूल, अनुवाद, पेज में ढूंढें, रीडर मोड, एक्सटेंशन, डार्क मोड, ब्राउज़र ज़ूम, और अपने-आप भरने की सुविधा.
दूसरी ओर, Canvas (और WebGL/WebGPU) की मदद से, पिक्सल के ग्रिड को चलाने के लिए लो-लेवल ऐक्सेस मिलता है. इससे ज़्यादा बेहतर 2D और 3D ग्राफ़िक बनाए जा सकते हैं. गेम और जटिल वेब ऐप्लिकेशन (जैसे, Google Docs या Figma) को बेहतर परफ़ॉर्मेंस के लिए, इस तरह के ऐक्सेस की ज़रूरत होती है. कैनवस, मूल रूप से पिक्सल की एक ग्रिड होती है. इसलिए, रिस्पॉन्सिव टेक्स्ट जैसी सुविधाओं के लिए, कस्टम यूज़र इंटरफ़ेस (यूआई) के जटिल लॉजिक की ज़रूरत होती थी. इससे आपके बंडल का साइज़ काफ़ी बढ़ जाता था. सबसे अहम बात यह है कि जब यूज़र इंटरफ़ेस (यूआई) को स्टैटिक कैनवस पिक्सल ग्रिड में लॉक कर दिया जाता है, तब डीओएम में इंटिग्रेट की गई ब्राउज़र की सभी सुविधाएं पूरी तरह से काम करना बंद कर देती हैं.
डीओएम को Canvas पर लाने के फ़ायदे
HTML-in-Canvas API, दोनों दुनियाओं को जोड़ने वाला पुल है. <canvas> एलिमेंट में एचटीएमएल रखकर और उसके ट्रांसफ़ॉर्म को सिंक करके, यह पक्का किया जाता है कि कॉन्टेंट पूरी तरह से इंटरैक्टिव बना रहे. साथ ही, सभी ब्राउज़र इंटिग्रेशन अपने-आप काम करें.
<canvas> एलिमेंट के अंदर यूज़र इंटरफ़ेस (यूआई) को डीओएम से मैनेज कराने पर, आपको ये फ़ायदे मिलते हैं:
- टेक्स्ट लेआउट और फ़ॉर्मैटिंग: टेक्स्ट लेआउट और फ़ॉर्मैटिंग को आसान बनाया गया है. इसमें सीएसएस स्टाइल लागू किए गए मल्टीलाइन या द्वि-दिशात्मक टेक्स्ट शामिल हैं.
- फ़ॉर्म कंट्रोल: फ़ॉर्म कंट्रोल को बेहतर बनाया गया है और इस्तेमाल करना आसान है. साथ ही, इन्हें पसंद के मुताबिक बनाने के कई विकल्प उपलब्ध हैं.
- टेक्स्ट चुनना, कॉपी/चिपकाना, और राइट क्लिक करना: उपयोगकर्ता, आपके 3D सीन में मौजूद टेक्स्ट को हाइलाइट कर सकते हैं. इसके अलावा, वे राइट क्लिक करके संदर्भ मेन्यू को नेटिव तौर पर खोल सकते हैं.
- सुलभता: कैनवस में रेंडर किया गया कॉन्टेंट, ऐक्सेसिबिलिटी ट्री को दिखता है. सुलभता सिस्टम, यूज़र इंटरफ़ेस (यूआई) को सामान्य एचटीएमएल की तरह पार्स कर सकते हैं. साथ ही, इसे स्क्रीन रीडर जैसे सिस्टम के लिए उपलब्ध करा सकते हैं.
- पेज में ढूंढें: उपयोगकर्ता, पेज में ढूंढें (Ctrl/Cmd+F) सुविधा का इस्तेमाल करके टेक्स्ट खोज सकते हैं. इसके बाद, ब्राउज़र उसे सीधे तौर पर आपके WebGL टेक्सचर में हाइलाइट करता है.
- इंडेक्स करने की सुविधा और एआई एजेंट के साथ इंटरफ़ेस करने की सुविधा: वेब क्रॉलर और एआई एजेंट, आपके 2D और 3D सीन में रेंडर किए गए टेक्स्ट को आसानी से इंडेक्स और पढ़ सकते हैं.
- एक्सटेंशन इंटिग्रेशन: ब्राउज़र एक्सटेंशन, नेटिव तौर पर काम करते हैं. उदाहरण के लिए, टेक्स्ट बदलने वाला एक्सटेंशन, आपके 3D मेश पर रेंडर किए गए टेक्स्ट को अपने-आप अपडेट करता है.
- DevTools इंटिग्रेशन: Chrome DevTools में सीधे तौर पर, WebGL/WebGPU यूज़र इंटरफ़ेस (यूआई) एलिमेंट के साथ-साथ अपने कैनवस कॉन्टेंट की जांच की जा सकती है. इंस्पेक्टर में सीएसएस स्टाइल में बदलाव करें और देखें कि 3D टेक्सचर पर वह तुरंत अपडेट हो जाता है!
इस्तेमाल के मुख्य उदाहरण
इस एपीआई की मदद से, कई डोमेन में शानदार काम किया जा सकता है:
- बड़े कैनवस वाले ऐप्लिकेशन: अब हैवीवेट वेब ऐप्लिकेशन, अपने कैनवस-ड्रिवन वर्कस्पेस में जटिल ऐप्लिकेशन यूज़र इंटरफ़ेस (यूआई) कॉम्पोनेंट को नेटिव तौर पर रेंडर कर सकते हैं. इससे ऐक्सेसिबिलिटी बेहतर होती है और बंडल का साइज़ कम होता है.
- 3D सीन और गेम: मार्केटिंग साइटें, शानदार WebXR अनुभव, और वेब गेम अब पूरी तरह से इंटरैक्टिव वेब यूज़र इंटरफ़ेस (यूआई) को 3D सीन में रख सकते हैं. जैसे, ऐसी 3D किताब जो असली DOM टेक्स्ट का इस्तेमाल करती है या ऐसा इन-गेम टर्मिनल जो कॉपी और चिपकाने की सुविधा को नेटिव तौर पर सपोर्ट करता है.
एपीआई का इस्तेमाल कैसे करें
एपीआई का इस्तेमाल तीन चरणों में होता है: कैनवस सेट अप करना, कैनवस में रेंडर करना, और सीएसएस ट्रांसफ़ॉर्म को अपडेट करना, ताकि ब्राउज़र को पता चल सके कि एलिमेंट स्क्रीन पर कहां मौजूद है.
ज़रूरी शर्तें
HTML-in-Canvas API, Chrome 148 से 150 तक के वर्शन में ऑरिजिन ट्रायल के तौर पर उपलब्ध है. अपनी साइट पर इसकी जांच करने के लिए, Chrome Canary 149 या इसके बाद के वर्शन का इस्तेमाल करें. साथ ही, chrome://flags/#canvas-draw-element फ़्लैग चालू करें. अन्य उपयोगकर्ताओं के लिए एपीआई चालू करने के लिए, ऑरिजिन ट्रायल के लिए रजिस्टर करें.
पहला चरण: कैनवस का बेसिक सेटअप
सबसे पहले, अपने <canvas> टैग में layoutsubtree एट्रिब्यूट जोड़ें. इससे ब्राउज़र को कैनवस में नेस्ट किए गए कॉन्टेंट के बारे में पता चलता है. साथ ही, उसे कैनवस में दिखाने के लिए तैयार किया जाता है और ऐक्सेसिबिलिटी ट्री के लिए उपलब्ध कराया जाता है.
<canvas id="canvas" style="width: 200px; height: 200px;" layoutsubtree>
<div id="form_element">
<label for="name">Name:</label> <input id="name" type="text">
</div>
</canvas>
कैनवस ग्रिड का साइज़ बदलना
रेंडर किए गए कॉन्टेंट के धुंधलेपन से बचने के लिए, पक्का करें कि कैनवस ग्रिड का साइज़, डिवाइस के स्केल फ़ैक्टर से मेल खाता हो.
const observer = new ResizeObserver(([entry]) => {
const dpc = entry.devicePixelContentBoxSize;
canvas.width = dpc ? dpc[0].inlineSize : Math.round(entry.contentRect.width * window.devicePixelRatio);
canvas.height = dpc ? dpc[0].blockSize : Math.round(entry.contentRect.height * window.devicePixelRatio);
});
const supportsDevicePixelContentBox =
typeof ResizeObserverEntry !== 'undefined' &&
'devicePixelContentBoxSize' in ResizeObserverEntry.prototype;
const options = supportsDevicePixelContentBox ? { box: 'device-pixel-content-box' } : {};
observer.observe(canvas, options);
दूसरा चरण: रेंडरिंग
2D कॉन्टेक्स्ट के लिए, drawElementImage तरीके का इस्तेमाल करें. ऐसा paint इवेंट के अंदर करें. यह इवेंट तब ट्रिगर होता है, जब एलिमेंट फिर से रेंडर होता है. उदाहरण के लिए, टेक्स्ट हाइलाइट करने या उपयोगकर्ता के इनपुट के दौरान. यह ज़रूरी है कि एलिमेंट के सीएसएस ट्रांसफ़ॉर्म को रिटर्न वैल्यू के साथ अपडेट किया जाए, ताकि इंटरैक्टिविटी काम करती रहे.
const ctx = document.getElementById('canvas').getContext('2d');
const form_element = document.getElementById('form_element');
const canvas = document.getElementById('canvas');
canvas.onpaint = () => {
ctx.reset();
// Draw the form element at x:0, y:0
let transform = ctx.drawElementImage(form_element, 0, 0);
// Use the transform returned later on...
};
WebGL की मदद से रेंडर करना
WebGL के लिए, texElementImage2D का इस्तेमाल किया जाता है. यह texImage2D की तरह ही काम करता है, लेकिन इसमें डीओएम एलिमेंट को सोर्स के तौर पर इस्तेमाल किया जाता है.
canvas.onpaint = () => {
if (gl.texElementImage2D) {
gl.texElementImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, form_element);
}
};
WebGPU की मदद से रेंडर करना
WebGPU, डिवाइस के कतार में लगे कामों के लिए copyElementImageToTexture तरीके का इस्तेमाल करता है. यह copyExternalImageToTexture के जैसा ही होता है:
canvas.onpaint = () => {
root.device.queue.copyElementImageToTexture(
valueElement,
{ texture: targetTexture }
);
};
तीसरा चरण: सीएसएस ट्रांसफ़ॉर्म को अपडेट करना
कैनवस में एलिमेंट रेंडर करने के बाद, आपको ब्राउज़र को यह बताना होगा कि वह कहां मौजूद है. इससे कैनवस और DOM के लेआउट के बीच, जगह के हिसाब से सिंक्रनाइज़ेशन पक्का होता है. यह इसलिए ज़रूरी है, ताकि ब्राउज़र इवेंट ज़ोन को सही तरीके से मैप कर सके. जैसे, उपयोगकर्ता ने कहां क्लिक किया या कहां होवर किया और एलिमेंट कहां रेंडर किया गया.
2D कॉन्टेक्स्ट वाले मामले में, रेंडरिंग कॉल से मिले ट्रांसफ़ॉर्म को .style.transform property पर लागू करें:
const ctx = document.getElementById('canvas').getContext('2d');
const form_element = document.getElementById('form_element');
const canvas = document.getElementById('canvas');
canvas.onpaint = () => {
ctx.reset();
// Draw the form element at x:0, y:0
let transform = ctx.drawElementImage(form_element, 0, 0);
// Sync the DOM location with the drawn location
form_element.style.transform = transform.toString();
};
WebGL या WebGPU की मदद से, किसी एलिमेंट की ऑन-स्क्रीन जगह इस बात पर निर्भर करती है कि शेडर कोड, आउटपुट टेक्सचर का इस्तेमाल कैसे करता है. इसे कैनवस रेंडरिंग कॉन्टेक्स्ट से नहीं निकाला जा सकता. हालांकि, अगर आपका शेडर प्रोग्राम, टेक्सचर को ड्रॉ करने के लिए मॉडल व्यू प्रोजेक्शन का इस्तेमाल करता है, तो element.getElementTransform() फ़ंक्शन का इस्तेमाल करके एक ऐसा ट्रांसफ़ॉर्म कंप्यूट किया जा सकता है जिसे drawElementImage() से मिली वैल्यू की तरह इस्तेमाल किया जा सकता है. इसके लिए, आपको यह करना होगा:
- WebGL एमवीपी मैट्रिक्स को डीओएम मैट्रिक्स में बदलें.
- एचटीएमएल एलिमेंट को सामान्य करें. एचटीएमएल एलिमेंट का साइज़, पिक्सल में तय किया जाता है. उदाहरण के लिए, 200 पिक्सल चौड़ा. हालांकि, WebGL आम तौर पर ऑब्जेक्ट को "यूनिट स्क्वेयर" के तौर पर देखता है. उदाहरण के लिए, 0 से 1 तक. अगर आपने सामान्य बनाने की प्रोसेस नहीं की, तो आपका 200 पिक्सल वाला बटन 200 गुना बड़ा दिखेगा.
- कैनवस व्यूपोर्ट पर मैप करें. यह चरण "रीस्केलिंग" फ़ेज़ है. यह यूनिट-स्पेस के हिसाब से तय की गई लंबाई-चौड़ाई को वापस स्क्रीन पर मौजूद
<canvas>एलिमेंट के असल पिक्सल डाइमेंशन के हिसाब से सेट कर देता है. यह Y-ऐक्सिस को भी फ़्लिप करता है, क्योंकि WebGL में ऊपर की ओर पॉज़िटिव होता है, लेकिन CSS में नीचे की ओर पॉज़िटिव होता है. - फ़ाइनल ट्रांसफ़ॉर्म का हिसाब लगाएं. मैट्रिक्स को इस क्रम में गुणा करें:
Viewport * MVP * Normalization.इन मैट्रिक्स को एक फ़ाइनल ट्रांसफ़ॉर्म में जोड़ने से एक "मैप" बनता है. इससे ब्राउज़र को यह पता चलता है कि 3D ड्राइंग के साथ अलाइन करने के लिए, एचटीएमएल एलिमेंट लेयर को कहां रखना चाहिए. - एचटीएमएल एलिमेंट पर ट्रांसफ़ॉर्म लागू करें. इससे एचटीएमएल एलिमेंट लेयर, रेंडर किए गए पिक्सल के ठीक ऊपर आ जाती है. इससे यह पक्का होता है कि जब कोई उपयोगकर्ता किसी बटन पर क्लिक करता है या टेक्स्ट चुनता है, तो वह असली एचटीएमएल एलिमेंट पर क्लिक कर रहा है.
if (canvas.getElementTransform) {
// 1. Convert WebGL MVP Matrix to DOM Matrix
const mvpDOM = new DOMMatrix(Array.from(htmlElementMVP));
// 2. Normalize the HTML element (pixels -> 1x1 unit square)
const width = targetHTMLElement.offsetWidth;
const height = targetHTMLElement.offsetHeight;
const cssToUnitSpace = new DOMMatrix()
.scale(1 / width, -1 / height, 1) // Shrink to unit size and flip Y
.translate(-width / 2, -height / 2); // Center the element
// 3. Map to the canvas viewport
const clipToCanvasViewport = new DOMMatrix()
.translate(canvas.width / 2, canvas.height / 2) // Move origin to center
.scale(canvas.width / 2, -canvas.height / 2, 1); // Stretch to canvas dimensions
// 4. Multiply: (Clip -> Pixels) * (MVP) * (pixels -> unit square)
const screenSpaceTransform = clipToCanvasViewport
.multiply(mvpDOM)
.multiply(cssToUnitSpace);
// 5. Apply to the transform
const computedTransform = canvas.getElementTransform(targetHTMLElement, screenSpaceTransform);
if (computedTransform) {
targetHTMLElement.style.transform = computedTransform.toString();
}
}
लाइब्रेरी और फ़्रेमवर्क के साथ काम करने की सुविधा
कुछ लोकप्रिय लाइब्रेरी में, HTML-in-Canvas सुविधा के लिए पहले से ही सहायता उपलब्ध है.
Three.js
मैट्रिक्स को मैन्युअल तरीके से अपडेट करना मुश्किल हो सकता है. इसलिए, फ़्रेमवर्क पहले से ही इसका इस्तेमाल कर रहे हैं. Three.js में, नए THREE.HTMLTexture का इस्तेमाल करके एक्सपेरिमेंट के तौर पर उपलब्ध सुविधा है:
const material = new THREE.MeshBasicMaterial();
material.map = new THREE.HTMLTexture(uiElement); // Pass the DOM element
const geometry = new THREE.BoxGeometry(1, 1, 1);
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
PlayCanvas
PlayCanvas, अपने टेक्सचर एपीआई का इस्तेमाल करके HTML-in-Canvas को भी सपोर्ट करता है:
// Wait for the 'paint' event to set the source
canvas.addEventListener('paint', () => {
htmlTexture.setSource(htmlElement);
}, { once: true });
canvas.requestPaint();
// Keep up to date
canvas.addEventListener('paint', onPaintUpload);
const material = new pc.StandardMaterial();
material.diffuseMap = htmlTexture;
material.update();
डेमो
डेमो आज़माने से पहले, पक्का करें कि आपका एनवायरमेंट सही तरीके से कॉन्फ़िगर किया गया हो.
एपीआई के इस्तेमाल के बारे में जानने के लिए, कई डेमो उपलब्ध हैं. हमें कम्यूनिटी से पहले ही क्रिएटिव सलूशन मिल रहे हैं. इनमें अनुवाद की जा सकने वाली 3D किताबें और यूज़र इंटरफ़ेस (यूआई) के ऐसे एलिमेंट शामिल हैं जो ग्लास शेडर से रिफ़्रैक्ट होते हैं:
- 3D बुक: WebGL की मदद से रेंडर की गई 3D बुक, जिसके पेजों के लिए एचटीएमएल लेआउट का इस्तेमाल किया जाता है. उपयोगकर्ता, सीएसएस की मदद से फ़ॉन्ट बदल सकते हैं. यह DOM पर आधारित है. इसलिए, इसमें पहले से मौजूद अनुवाद की सुविधा तुरंत काम करती है. साथ ही, एआई एजेंट कम समय में टेक्स्ट को निकाल सकते हैं.
- इंटरैक्टिव 3D यूज़र इंटरफ़ेस (यूआई): WebGPU जेली स्लाइडर, जो 3D मॉडल के आधार पर रोशनी को रिफ़्रैक्ट करता है. साथ ही, यह अब भी स्टैंडर्ड एचटीएमएल
<input type="range">स्टेप एट्रिब्यूट के हिसाब से काम करता है. - ऐनिमेशन वाली बनावट: यह एक डाइनैमिक 3D बिलबोर्ड है. इसमें DOM का इस्तेमाल करके, ऐनिमेशन वाली SVG पेंसिल को सीधे तौर पर WebGL टेक्सचर में रेंडर किया जाता है. इसके लिए, कस्टम ऐनिमेशन लूप की ज़रूरत नहीं होती.
- अपवर्तक ओवरले: यह एक इंटरैक्टिव टाइपोग्राफ़ी लेयर है. इसे हिलते हुए 3D कर्सर से खराब किया गया है. हालांकि, इसे पूरी तरह से चुना जा सकता है. साथ ही, 'पेज में ढूंढें' सुविधा का इस्तेमाल करके खोजा जा सकता है.
कम्यूनिटी के बनाए गए डेमो का कलेक्शन देखें. अगर आपको इस कलेक्शन में अपना HTML-in-Canvas डेमो दिखाना है, तो उसे जोड़ने के लिए पुल का अनुरोध बनाएं.
सीमाएं
एपीआई में कई सुविधाएं उपलब्ध हैं, लेकिन इसकी कुछ सीमाएं हैं:
- क्रॉस-ऑरिजिन कॉन्टेंट: सुरक्षा और निजता से जुड़ी वजहों से, यह एपीआई क्रॉस-ऑरिजिन iframe कॉन्टेंट के साथ काम नहीं करता.
- मुख्य थ्रेड स्क्रोलिंग: एचटीएमएल-इन-कैनवस को JavaScript की मदद से बनाया जाता है. इसका मतलब है कि स्क्रोलिंग और ऐनिमेशन, JavaScript से अलग अपडेट नहीं हो सकते. हालांकि, कैनवस के बाहर ऐसा किया जा सकता है. डेवलपर को इस बात पर ध्यान देना चाहिए कि पूरे कैनवस को स्क्रोल करने के बजाय, कैनवस में स्क्रोल करने वाला कॉन्टेंट डालने से परफ़ॉर्मेंस पर क्या असर पड़ता है.
सुझाव/राय दें या शिकायत करें
अगर आपने HTML-in-Canvas API को आज़माया है, तो हमें बताएं कि आपको यह कैसा लगा! ऑरिजिन ट्रायल के लिए साइन अप करें. इससे आपको अपनी साइट पर इस सुविधा को चालू करने का मौका मिलेगा. इससे हमें एपीआई डिज़ाइन को बेहतर बनाने में मदद मिलेगी. कोई सुझाव/राय देने या शिकायत करने के लिए, समस्या की शिकायत करें.
संसाधन
- Three.js में HTML-in-Canvas की सुविधा
- Three.js डेमो में HTML-in-Canvas
- PlayCanvas में HTML-in-Canvas की सुविधा: डेवलपर दस्तावेज़
- PlayCanvas डेमो में HTML-in-Canvas
- HTML-in-Canvas: Explainer
- HTML-in-Canvas के लिए, एआई कोडिंग टूल के लिए मॉडर्न वेब गाइडेंस
- HTML-in-Canvas के लिए Chrome.dev डेमो
- कम्यूनिटी की ओर से, HTML-in-Canvas के डेमो का बेहतरीन कलेक्शन