Chrome के साथ बनाएं

LEGO® ब्रिक्स को मल्टी-डिवाइस वेब पर लाना

Build with Chrome, डेस्कटॉप पर Chrome का इस्तेमाल करने वालों के लिए एक मज़ेदार प्रयोग है. इसे शुरुआत में ऑस्ट्रेलिया में लॉन्च किया गया था. इसे 2014 में फिर से रिलीज़ किया गया था. इसे LEGO® MOVIETM के साथ टाई-इन करने और मोबाइल डिवाइसों के लिए नई सुविधा जोड़ी गई है. इसे 2014 में फिर से रिलीज़ किया गया था. इस लेख में, हम प्रोजेक्ट से जुड़ी कुछ जानकारी शेयर करेंगे. इनमें खास तौर पर, सिर्फ़ डेस्कटॉप के लिए इस्तेमाल होने वाले टूल को छोड़कर मल्टी-स्क्रीन पर काम करने वाले टूल पर स्विच करने के बारे में बताया गया है. यह टूल माउस और टच इनपुट, दोनों के साथ काम करता है.

Chrome के साथ बिल्ड करने का इतिहास

Build with Chrome का पहला वर्शन साल 2012 में ऑस्ट्रेलिया में लॉन्च किया गया था. हम वेब की शक्ति को बिलकुल नए तरीके से दिखाना और Chrome को बिलकुल नए दर्शकों तक पहुंचाना चाहते थे.

साइट के दो मुख्य हिस्से थे: "बिल्ड" मोड, जहां उपयोगकर्ता LEGO ब्रिक्स का इस्तेमाल करके क्रिएशन बना सकते हैं और "एक्सप्लोर करें" मोड, ताकि Google Maps के LEGO के वर्शन पर इन क्रिएशन को ब्राउज़ किया जा सके.

उपयोगकर्ताओं को सर्वश्रेष्ठ LEGO इमारत का अनुभव देने के लिए इंटरैक्टिव 3D ज़रूरी था. साल 2012 में, WebGL सार्वजनिक तौर पर डेस्कटॉप ब्राउज़र पर ही उपलब्ध था. इसलिए, बिल्ड को सिर्फ़ डेस्कटॉप के लिए बनाया गया था. Explore ने क्रिएशन को दिखाने के लिए Google Maps का इस्तेमाल किया है. हालांकि, काफ़ी हद तक ज़ूम करने पर, क्रिएशन को 3D में दिखाते हुए, मैप के WebGL पर काम करने लगा. इस दौरान, Google Maps को बेसप्लेट टेक्स्चर के तौर पर इस्तेमाल किया जा रहा है. हमें उम्मीद है कि हम ऐसा माहौल बना पाएंगे जहां LEGO सभी उम्र के लोग आसानी से अपनी क्रिएटिविटी दिखा सकें और एक-दूसरे के बनाए हुए कॉन्टेंट को एक्सप्लोर कर सकें.

साल 2013 में, हमने Build with Chrome को नई वेब टेक्नोलॉजी पर उपलब्ध कराने का फ़ैसला लिया. उन टेक्नोलॉजी में Android के लिए Chrome में WebGL भी शामिल था. इससे, Build with Chrome को मोबाइल पर इस्तेमाल करने के अनुभव को बेहतर बनाया जा सकता था. शुरू करने के लिए, हमने "बिल्डर टूल" के हार्डवेयर के बारे में सवाल पूछने से पहले टच प्रोटोटाइप डेवलप किए हैं. इससे यह समझने में मदद मिलती है कि लोगों को मोबाइल ऐप्लिकेशन के मुकाबले, ब्राउज़र पर किस तरह के जेस्चर का सामना करना पड़ता है.

एक प्रतिक्रियाशील फ़्रंट-एंड

हमें टच और माउस इनपुट दोनों वाले डिवाइसों पर काम करने की ज़रूरत थी. हालांकि, छोटी टच स्क्रीन पर समान यूज़र इंटरफ़ेस (यूआई) का इस्तेमाल करना, जगह कम होने की वजह से सबसे बेहतर समाधान साबित हुआ.

बिल्ड में बहुत सारी इंटरैक्टिविटी चलती है: ज़ूम इन और आउट करना, ईंटों के रंग बदलना, और ईंटों को चुनना, घुमाना, और लगाना. यह एक ऐसा टूल है जहां उपयोगकर्ता अक्सर बहुत ज़्यादा समय बिताते हैं. इसलिए, यह ज़रूरी है कि उनके पास हर उस चीज़ का तुरंत ऐक्सेस हो जिसका वे अक्सर इस्तेमाल करते हैं और उन्हें इससे इंटरैक्ट करने में कोई परेशानी नहीं होनी चाहिए.

हाई इंटरैक्टिव टच ऐप्लिकेशन डिज़ाइन करते समय, आपको स्क्रीन पर तेज़ी से छोटा लगने वाला एहसास होता है. साथ ही, इंटरैक्ट करते समय उपयोगकर्ताओं की उंगलियां ज़्यादातर स्क्रीन को कवर कर लेती हैं. बिल्डर के साथ काम करते समय यह बात हमें साफ़ तौर पर दिख गई. डिज़ाइन करते समय, आपको ग्राफ़िक में पिक्सल के बजाय स्क्रीन के फ़िज़िकल साइज़ पर ध्यान देना होगा. असली कॉन्टेंट के लिए ज़्यादा से ज़्यादा स्क्रीन रीयल एस्टेट देखने के लिए, बटन और कंट्रोल की संख्या कम करना अहम हो जाता है.

हमारा लक्ष्य, बिल्ड को टच डिवाइस पर स्वाभाविक लगने जैसा बनाना था. इसमें न सिर्फ़ डेस्कटॉप के ओरिजनल इंप्लिमेंटेशन में टच इनपुट जोड़ना था, बल्कि इसे वैसा ही महसूस कराना था जैसा कि इसे टच करने के लिए बनाया गया था. आखिर में हमने यूज़र इंटरफ़ेस (यूआई) के दो वैरिएशन बनाए, एक डेस्कटॉप और बड़ी स्क्रीन वाले टैबलेट के लिए और दूसरा छोटी स्क्रीन वाले मोबाइल डिवाइस के लिए. अगर संभव हो, तो एक ही इंप्लीमेंटेशन का इस्तेमाल करना और अलग-अलग मोड के बीच आसान ट्रांज़िशन करना सबसे अच्छा होता है. इस मामले में, हमें पता चला कि इन दोनों मोड के अनुभव में इतना अंतर था कि हमने एक खास ब्रेकपॉइंट पर भरोसा करने का फ़ैसला किया. दोनों वर्शन में कई सुविधाएं एक जैसी हैं. हमने ज़्यादातर चीज़ों को सिर्फ़ एक कोड लागू करके करने की कोशिश की, लेकिन यूज़र इंटरफ़ेस (यूआई) के कुछ आसपेक्ट, दोनों के बीच अलग-अलग तरह से काम करते हैं.

हम मोबाइल डिवाइस का पता लगाने के लिए उपयोगकर्ता-एजेंट डेटा का इस्तेमाल करते हैं. इसके बाद, हम व्यूपोर्ट के साइज़ की जांच करके यह तय करते हैं कि छोटे स्क्रीन वाले मोबाइल यूज़र इंटरफ़ेस (यूआई) का इस्तेमाल किया जाना चाहिए या नहीं. "बड़ी स्क्रीन" के लिए ब्रेकपॉइंट चुनना थोड़ा मुश्किल है, क्योंकि फ़िज़िकल स्क्रीन साइज़ की भरोसेमंद वैल्यू पाना मुश्किल होता है. अच्छी बात यह है कि हमारे मामले में, अगर हम बड़ी स्क्रीन वाले टच डिवाइस पर छोटी स्क्रीन का यूज़र इंटरफ़ेस (यूआई) दिखाएं, तो इससे ज़्यादा फ़र्क़ नहीं पड़ता. ऐसा इसलिए होता है, क्योंकि यह टूल अब भी ठीक से काम करेगा, बस कुछ बटन बहुत बड़े लग सकते हैं. आखिर में, हमने ब्रेकपॉइंट को 1000 पिक्सल पर सेट किया है. अगर साइट को 1000 पिक्सल से ज़्यादा चौड़ी विंडो (लैंडस्केप मोड में) से लोड किया जाता है, तो आपको बड़ी स्क्रीन वाला वर्शन मिलेगा.

चलिए, दोनों स्क्रीन साइज़ और अनुभवों के बारे में थोड़ी बात करते हैं:

बड़ी स्क्रीन, माउस और छूकर देखने की सुविधा

बड़ी स्क्रीन वाले वर्शन को सभी डेस्कटॉप कंप्यूटर पर, माउस से चलाने की सुविधा मिलती है. साथ ही, बड़ी स्क्रीन वाले डिवाइसों (जैसे कि Google Nexus 10) को छुआ जाता है. यह वर्शन, मूल डेस्कटॉप समाधान से मिलता-जुलता है, जिसमें तरह-तरह के नेविगेशन कंट्रोल उपलब्ध हैं. हालांकि, हमने टच सपोर्ट और हाथ के कुछ जेस्चर (हाव-भाव) की सुविधा जोड़ी है. हम विंडो के साइज़ के हिसाब से यूज़र इंटरफ़ेस (यूआई) में बदलाव करते हैं. इसलिए, जब कोई उपयोगकर्ता विंडो का साइज़ बदलता है, तो हो सकता है कि वह कुछ यूज़र इंटरफ़ेस (यूआई) को हटा दे या उसका साइज़ बदल दे. ऐसा करने के लिए, हम सीएसएस मीडिया क्वेरी का इस्तेमाल करते हैं.

उदाहरण: जब उपलब्ध ऊंचाई 730 पिक्सल से कम होती है, तब एक्सप्लोर मोड में ज़ूम-स्लाइडर कंट्रोल छिपा होता है:

@media only screen and (max-height: 730px) {
    .zoom-slider {
        display: none;
    }
}

छोटी स्क्रीन, सिर्फ़ छूकर इस्तेमाल करने की सुविधा

यह वर्शन मोबाइल डिवाइस और छोटे टैबलेट (लक्ष्य डिवाइस Nexus 4 और Nexus 7) पर उपलब्ध कराया जाता है. इस वर्शन के लिए मल्टी-टच सपोर्ट की ज़रूरत है.

छोटी स्क्रीन वाले डिवाइसों पर, हमें ज़्यादा से ज़्यादा स्क्रीन रीयल एस्टेट देने की ज़रूरत होती है. इसलिए, हमने जगह को बढ़ाने के लिए कुछ सुधार किए हैं. इनमें अक्सर इस्तेमाल नहीं किए जाने वाले एलिमेंट को स्क्रीन से हटा दिया जाता है:

  • बिल्ड ब्रिक चुनने वाला टूल, इमारत बनाते समय रंग चुनने के विकल्प को छोटा करता है.
  • हमने ज़ूम और ओरिएंटेशन कंट्रोल को मल्टी-टच जेस्चर से बदल दिया है.
  • कुछ अतिरिक्त स्क्रीन रीयल एस्टेट के लिए भी Chrome फ़ुलस्क्रीन की सुविधा से मदद मिलती है.
बड़ी स्क्रीन पर बनाएं
बड़ी स्क्रीन पर बनाएं. ब्रिक सिलेक्टर हमेशा दिखता है और दाईं ओर कुछ कंट्रोल होते हैं.
छोटी स्क्रीन पर बनाएं
छोटी स्क्रीन पर बनाएं. ब्रिक चुनने वाले टूल को छोटा कर दिया गया है और कुछ बटन हटा दिए गए हैं.

WebGL की परफ़ॉर्मेंस और सहायता

मॉडर्न टच डिवाइसों में काफ़ी दमदार जीपीयू होते हैं, लेकिन वे अब भी अपने डेस्कटॉप वाले जीपीयू से काफ़ी दूर हैं. इसलिए, हमें पता था कि इनकी परफ़ॉर्मेंस को लेकर कुछ चुनौतियों का सामना करना पड़ सकता है. खासकर, एक्सप्लोर 3D मोड में, जहां हमें एक साथ कई क्रिएशन रेंडर करने की ज़रूरत होती है.

रचनात्मक रूप से, हम जटिल आकार और पारदर्शिता वाली कुछ नई तरह की ईंटों को जोड़ना चाहते थे -- ऐसी सुविधाएं जो आम तौर पर जीपीयू पर बहुत ज़्यादा होती हैं. हालांकि, हमें पुराने वर्शन के हिसाब से काम करना था और पहले वर्शन से बनाए गए कॉन्टेंट का समर्थन करना जारी रखना था. इसलिए, हम कोई भी नई पाबंदी नहीं लगा सके. जैसे, क्रिएशन में ईंटों की कुल संख्या को कम करना.

बिल्ड के पहले वर्शन में इसमें ईंटों की ज़्यादा से ज़्यादा सीमा होती थी, जिनका इस्तेमाल एक निर्माण में किया जा सकता था. वहां एक "ईंट-मीटर" लगा था, जो बता रहा था कि कितनी ईंट बची थीं. नए लागू करने के दौरान, सामान्य ईंटों की तुलना में ब्रिक-मीटर को ज़्यादा असर देने के लिए हमें कुछ नई ईंटों का इस्तेमाल करना पड़ा. इसलिए, ईंटों की कुल संख्या को थोड़ा कम किया गया. यह अच्छा परफ़ॉर्मेंस बनाए रखने के साथ-साथ, कारोबार में नई ईंटों को शामिल करने का एक तरीका था.

'एक्सप्लोर 3D मोड' में एक ही समय में बहुत कुछ होता रहता है. जैसे, बेस प्लेट टेक्स्चर लोड करना, क्रिएशन लोड करना, क्रिएशन को ऐनिमेट और रेंडर करना वगैरह. इसके लिए, जीपीयू और सीपीयू, दोनों की ज़रूरत पड़ती है. इसलिए, हमने Chrome DevTools में फ़्रेम प्रोफ़ाइल बनाने के बहुत सारे काम किए हैं, ताकि इन हिस्सों को ज़्यादा से ज़्यादा ऑप्टिमाइज़ किया जा सके. हमने मोबाइल डिवाइस पर क्रिएशन को थोड़ा और ज़ूम करने का फ़ैसला किया, ताकि हमें एक साथ कई क्रिएशन रेंडर न करनी पड़ें.

कुछ डिवाइसों पर हमें WebGL शेडर के कुछ हिस्सों को फिर से इस्तेमाल करना और आसान बनाना था. हालांकि, हमें हमेशा इसे हल करने और आगे बढ़ने का एक तरीका मिला.

गैर-WebGL डिवाइसों के साथ काम करने की सुविधा

हम चाहते थे कि साइट कुछ हद तक इस्तेमाल करने लायक हो, भले ही वेबसाइट पर आने वाले व्यक्ति के डिवाइस पर WebGL काम न करता हो. कभी-कभी कैनवस समाधान या CSS3D सुविधाओं का इस्तेमाल करके, 3D को आसान तरीके से दिखाने के कई तरीके होते हैं. माफ़ करें, हमें WebGL का इस्तेमाल किए बिना बिल्ड और 3D सुविधाओं को एक्सप्लोर करने का अच्छा तरीका नहीं मिला.

एक जैसा बनाए रखने के लिए, सभी प्लैटफ़ॉर्म पर क्रिएशन का विज़ुअल स्टाइल एक जैसा होना चाहिए. हम वीडियो को 2.5D वर्शन पर भी उपलब्ध कराने की कोशिश कर सकते थे. हालांकि, इससे कुछ अलग तरीकों से क्रिएशन का लुक अलग हो सकता था. हमें यह भी तय करना था कि Create with Chrome के पहले वर्शन से बनाई गई क्रिएशन, पहले की तरह साइट के नए वर्शन पर पहले जैसी ही दिखे और साइट के नए वर्शन पर भी उतनी ही आसानी से चलें.

एक्सप्लोर करें 2D मोड अब भी गैर-WebGL डिवाइस के लिए ऐक्सेस किया जा सकता है, भले ही आप नई क्रिएशन नहीं बना सकते या 3D में एक्सप्लोर नहीं कर सकते. इससे उपयोगकर्ताओं को प्रोजेक्ट की बारीकियों के बारे में अब भी पता चल सकता है. साथ ही, यह भी पता चल सकता है कि WebGL के साथ काम करने वाले डिवाइस पर इस टूल का इस्तेमाल करके क्या बनाया जा सकता है. ऐसा हो सकता है कि उपयोगकर्ताओं के लिए यह साइट उतनी काम की न हो जितनी WebGL की सुविधा के बिना काम करती है, लेकिन इसे कम से कम एक टीज़र की तरह काम करना चाहिए. साथ ही, इस साइट को आज़माने के लिए उन्हें शामिल करना चाहिए.

कभी-कभी WebGL समाधानों के लिए फ़ॉलबैक वर्शन रखना मुमकिन नहीं होता. इसकी कई वजहें हो सकती हैं; परफ़ॉर्मेंस, विज़ुअल स्टाइल, डेवलपमेंट और रखरखाव का खर्च वगैरह. हालांकि, जब आप फ़ॉलबैक लागू न करने का फ़ैसला करते हैं, तो आपको कम से कम WebGL का इस्तेमाल न करने वाले विज़िटर का ध्यान रखना चाहिए. साथ ही, यह बताना चाहिए कि वे साइट को पूरी तरह से ऐक्सेस क्यों नहीं कर सकते. साथ ही, WebGL के साथ काम करने वाले ब्राउज़र का इस्तेमाल करके समस्या को हल करने के तरीके के बारे में निर्देश देना चाहिए.

ऐसेट मैनेजमेंट

साल 2013 में, Google ने Google Maps का नया वर्शन पेश किया. लॉन्च होने के बाद से, Google ने यूज़र इंटरफ़ेस (यूआई) में सबसे अहम बदलाव किए हैं. इसलिए, हमने Build with Chrome को फिर से डिज़ाइन करने का फ़ैसला किया, ताकि वह नए Google Maps के यूज़र इंटरफ़ेस (यूआई) में फ़िट हो सके. ऐसा करने के लिए, हमने अन्य पहलुओं को भी रीडिज़ाइन किया. नया डिज़ाइन कुछ हद तक फ़्लैट है, लेकिन उसमें चमकदार रंग मौजूद हैं और आकार आसान हैं. इससे हम इमेज का इस्तेमाल कम करते हुए, कई यूज़र इंटरफ़ेस (यूआई) एलिमेंट पर सामान्य सीएसएस का इस्तेमाल कर पाए.

एक्सप्लोर में हमें बहुत सारी इमेज लोड करनी होंगी. क्रिएशन के लिए थंबनेल इमेज, बेसप्लेट के लिए मैप की बनावट, और असल 3D क्रिएशन के लिए थंबनेल इमेज लोड होंगी. हम इस बात का खास ध्यान रखते हैं कि लगातार नई इमेज लोड करते समय मेमोरी लीक न हो.

3D क्रिएशन को PNG इमेज के तौर पर पैकेज किए गए कस्टम फ़ाइल फ़ॉर्मैट में स्टोर किया जाता है. 3D क्रिएशन के डेटा को इमेज के तौर पर सेव करके रखने से, हम डेटा को सीधे उन शेडर को भेज पाते हैं जो क्रिएशन को रेंडर करते हैं.

उपयोगकर्ताओं की जनरेट की गई सभी इमेज के लिए, डिज़ाइन की वजह से हमें सभी प्लैटफ़ॉर्म पर एक ही साइज़ की इमेज का इस्तेमाल करने की सुविधा मिली. इस तरह, स्टोरेज और बैंडविथ का इस्तेमाल कम हुआ.

स्क्रीन ओरिएंटेशन मैनेज करना

यह भूलना आसान है कि पोर्ट्रेट से लैंडस्केप मोड में या बदलते समय स्क्रीन के आसपेक्ट रेशियो में कितना बदलाव होता है. आपको मोबाइल डिवाइसों को अपनाने के दौरान शुरू से ही इस पर ध्यान देना चाहिए.

स्क्रोल की सुविधा वाली पारंपरिक वेबसाइट पर, कॉन्टेंट और मेन्यू को फिर से व्यवस्थित करने वाली रिस्पॉन्सिव साइट पाने के लिए, सीएसएस के नियम लागू किए जा सकते हैं. स्क्रोल करने की सुविधा का इस्तेमाल करने पर, इसे आसानी से मैनेज किया जा सकता है.

हमने इस तरीके का इस्तेमाल बिल्ड के साथ भी किया था. हालांकि, हम लेआउट को हल करने के मामले में थोड़ा सीमित थे. ऐसा इसलिए, क्योंकि हमारे पास कॉन्टेंट का हर समय दिखने के साथ-साथ, कई कंट्रोल और बटन का क्विक ऐक्सेस होना चाहिए. समाचार साइटों जैसी सिर्फ़ कॉन्टेंट वाली साइटों के लिए, फ़्लूइड लेआउट बहुत काम का होता है, लेकिन हमारे जैसे गेम ऐप्लिकेशन के लिए यह मुश्किल काम था. ऐसे लेआउट को ढूंढना चुनौती बन गया जो लैंडस्केप और पोर्ट्रेट ओरिएंटेशन, दोनों में काम करता हो. साथ ही, यह कॉन्टेंट के बारे में अच्छी तरह से खास जानकारी और बातचीत का आसान तरीका बनाए रखता था. आखिर में, हमने बिल्ड को सिर्फ़ लैंडस्केप में रखने का फ़ैसला किया और हम उपयोगकर्ता को डिवाइस घुमाने के लिए कहते हैं.

दोनों ओरिएंटेशन में, एक्सप्लोर करना बहुत आसान था. हमें सिर्फ़ एक जैसा अनुभव पाने के लिए, स्क्रीन की दिशा के आधार पर 3D के ज़ूम लेवल को एडजस्ट करना था.

ज़्यादातर कॉन्टेंट लेआउट, सीएसएस से कंट्रोल होता है. हालांकि, इसे JavaScript में लागू करने के लिए, ओरिएंटेशन से जुड़े कुछ कॉन्टेंट की ज़रूरत होती है. हमें पता चला कि ओरिएंटेशन की पहचान करने के लिए, window.Orइंटेशन का इस्तेमाल करने के लिए कोई अच्छा क्रॉस-डिवाइस सलूशन मौजूद नहीं है. इसलिए, आखिर में हम डिवाइस के ओरिएंटेशन की पहचान करने के लिए, window.innerWidth और window.innerHeight की ही तुलना कर रहे थे.

if( window.innerWidth > window.innerHeight ){
  //landscape
} else {
  //portrait
}

टच सहायता जोड़ना

वेब कॉन्टेंट के लिए, छूकर इस्तेमाल करने की सुविधा जोड़ना काफ़ी आसान है. क्लिक इवेंट जैसी बुनियादी इंटरैक्टिविटी, डेस्कटॉप और टच-सुविधा वाले डिवाइसों पर एक ही तरह से काम करती है. हालांकि, अगर ज़्यादा बेहतर इंटरैक्शन की बात करें, तो आपको टच इवेंट को भी मैनेज करना होगा. जैसे, टचस्टार्ट, टचस्क्रीन, और टचएंड. इस लेख में इन इवेंट के इस्तेमाल की बुनियादी बातें बताई गई हैं. Internet Explorer में टच इवेंट का इस्तेमाल नहीं किया जा सकता. इसके बजाय, यह पॉइंटर इवेंट (पॉइंटरडाउन, पॉइंटरमूव, पॉइंटरअप) का इस्तेमाल करता है. पॉइंटर इवेंट को मानक तय करने के लिए W3C को सबमिट किया गया है. हालांकि, फ़िलहाल इन्हें सिर्फ़ Internet Explorer में ही लागू किया गया है.

'एक्सप्लोर 3D मोड' में हम Google Maps के मानक नेविगेशन वाले ही नेविगेशन चाहते थे. मैप पर पैन करने के लिए एक उंगली का इस्तेमाल किया जाता था और ज़ूम करने के लिए दो उंगलियों से पिंच किया जाता था. क्रिएशन 3D में देखे जा सकते हैं. इसलिए, हमने दो उंगलियों से घुमाने का जेस्चर भी जोड़ा है. आम तौर पर यह कुछ ऐसा होता है जिसके लिए टच-इवेंट का इस्तेमाल करना होगा.

ज़्यादा कंप्यूटिंग से बचने का अच्छा तरीका है, जैसे कि इवेंट हैंडलर में 3D को अपडेट या रेंडर करना. इसके बजाय, टच इनपुट को किसी वैरिएबल में स्टोर करें और requestAnimationFrame रेंडर लूप में इनपुट पर प्रतिक्रिया दें. इससे, माउस की वैल्यू को आसानी से लागू किया जा सकता है. आपको सिर्फ़ माउस की वैल्यू को एक ही वैरिएबल में स्टोर करना होता है.

इनपुट को स्टोर करने के लिए, किसी ऑब्जेक्ट को शुरू करें और टचस्टार्ट इवेंट लिसनर जोड़ें. हर इवेंट हैंडलर में, हम event.preventDefault() को कॉल करते हैं. ऐसा करने से ब्राउज़र, टच इवेंट को लगातार प्रोसेस नहीं कर पाता. इस वजह से, पूरे पेज को स्क्रोल करने या स्केल करने जैसी कुछ गड़बड़ियां हो सकती हैं.

var input = {dragStartX:0, dragStartY:0, dragX:0, dragY:0, dragDX:0, dragDY:0, dragging:false};
plateContainer.addEventListener('touchstart', onTouchStart);

function onTouchStart(event) {
  event.preventDefault();
  if( event.touches.length === 1){
    handleDragStart(event.touches[0].clientX , event.touches[0].clientY);
    //start listening to all needed touchevents to implement the dragging
    document.addEventListener('touchmove', onTouchMove);
    document.addEventListener('touchend', onTouchEnd);
    document.addEventListener('touchcancel', onTouchEnd);
  }
}

function onTouchMove(event) {
  event.preventDefault();
  if( event.touches.length === 1){
    handleDragging(event.touches[0].clientX, event.touches[0].clientY);
  }
}

function onTouchEnd(event) {
  event.preventDefault();
  if( event.touches.length === 0){
    handleDragStop();
    //remove all eventlisteners but touchstart to minimize number of eventlisteners
    document.removeEventListener('touchmove', onTouchMove);
    document.removeEventListener('touchend', onTouchEnd);
    //also listen to touchcancel event to avoid unexpected behavior when switching tabs and some other situations
    document.removeEventListener('touchcancel', onTouchEnd);
  }
}

हम इवेंट हैंडलर में इनपुट का असल स्टोरेज इस्तेमाल नहीं कर रहे हैं, बल्कि इसके बजाय हम अलग हैंडलर में हैंडल का इस्तेमाल कर रहे हैं: छिपकली से हैंडलिंग को आगे बढ़ाना, हैंडल खींचे जाने का तरीका और हैंडलड्रैगस्टॉप. ऐसा इसलिए, क्योंकि हम चाहते हैं कि इन्हें माउस इवेंट हैंडलर से भी कॉल किया जा सके. ध्यान रखें कि भले ही इसकी संभावना कम है, लेकिन उपयोगकर्ता एक ही समय पर छूकर और माउस का इस्तेमाल कर सकता है. इस मामले को सीधे तौर पर हैंडल करने के बजाय, हम इस बात का ध्यान रखते हैं कि किसी भी तरह की गड़बड़ी न हो.

function handleDragStart(x ,y ){
  input.dragging = true;
  input.dragStartX = input.dragX = x;
  input.dragStartY = input.dragY = y;
}

function handleDragging(x ,y ){
  if(input.dragging) {
    input.dragDX = x - input.dragX;
    input.dragDY = y - input.dragY;
    input.dragX = x;
    input.dragY = y;
  }
}

function handleDragStop(){
  if(input.dragging) {
    input.dragging = false;
    input.dragDX = 0;
    input.dragDY = 0;
  }
}

Touchmove पर आधारित ऐनिमेशन करते समय, आखिरी इवेंट के बाद से डेल्टा मूव को सेव करना भी अक्सर मददगार होता है. उदाहरण के लिए, हमने Explore में सभी बेस प्लेट पर चलते समय, कैमरे की वेलोसिटी के पैरामीटर के तौर पर इसका इस्तेमाल किया. इसकी वजह यह है कि आप बेस प्लेट को नहीं खींच रहे हैं, बल्कि कैमरे को मूव कर रहे हैं.

function onAnimationFrame() {
  requestAnimationFrame( onAnimationFrame );

  //execute animation based on input.dragDX, input.dragDY, input.dragX or input.dragY
 /*
  /
  */

  //because touchmove is only fired when finger is actually moving we need to reset the delta values each frame
  input.dragDX=0;
  input.dragDY=0;
}

एम्बेड किए गए उदाहरण: टच इवेंट का इस्तेमाल करके ऑब्जेक्ट को खींचना. बिल्ड with Chrome में 3D मैप को एक्सप्लोर करने के दौरान, इसी तरह लागू करना: http://cdpn.io/qDxvo

मल्टी-टच जेस्चर

Hammer या QuoJS जैसे कई फ़्रेमवर्क या लाइब्रेरी मौजूद हैं, जो मल्टी-टच जेस्चर के मैनेजमेंट को आसान बना सकती हैं. हालांकि, अगर आपको कई जेस्चर जोड़ना और पूरा कंट्रोल चाहिए, तो कभी-कभी शुरुआत से ऐसा करना सबसे अच्छा होता है.

पिंच करने और घुमाने वाले जेस्चर मैनेज करने के लिए, हम स्क्रीन पर दूसरी उंगली डालने पर, दो उंगलियों के बीच की दूरी और ऐंगल सेव करते हैं:

//variables representing the actual scale/rotation of the object we are affecting
var currentScale = 1;
var currentRotation = 0;

function onTouchStart(event) {
  event.preventDefault();
  if( event.touches.length === 1){
    handleDragStart(event.touches[0].clientX , event.touches[0].clientY);
  }else if( event.touches.length === 2 ){
    handleGestureStart(event.touches[0].clientX, event.touches[0].clientY, event.touches[1].clientX, event.touches[1].clientY );
  }
}

function handleGestureStart(x1, y1, x2, y2){
  input.isGesture = true;
  //calculate distance and angle between fingers
  var dx = x2 - x1;
  var dy = y2 - y1;
  input.touchStartDistance=Math.sqrt(dx*dx+dy*dy);
  input.touchStartAngle=Math.atan2(dy,dx);
  //we also store the current scale and rotation of the actual object we are affecting. This is needed to support incremental rotation/scaling. We can't assume that an object is always the same scale when gesture starts.
  input.startScale=currentScale;
  input.startAngle=currentRotation;
}

टचमूव इवेंट में, हम इन दो उंगलियों के बीच की दूरी और ऐंगल को लगातार मापते हैं. इसके बाद, शुरुआती दूरी और मौजूदा दूरी के बीच के अंतर का इस्तेमाल स्केल सेट करने के लिए किया जाता है. शुरुआती कोण और मौजूदा ऐंगल के बीच के अंतर का इस्तेमाल ऐंगल सेट करने के लिए किया जाता है.

function onTouchMove(event) {
  event.preventDefault();
  if( event.touches.length  === 1){
    handleDragging(event.touches[0].clientX, event.touches[0].clientY);
  }else if( event.touches.length === 2 ){
    handleGesture(event.touches[0].clientX, event.touches[0].clientY, event.touches[1].clientX, event.touches[1].clientY );
  }
}

function handleGesture(x1, y1, x2, y2){
  if(input.isGesture){
    //calculate distance and angle between fingers
    var dx = x2 - x1;
    var dy = y2 - y1;
    var touchDistance = Math.sqrt(dx*dx+dy*dy);
    var touchAngle = Math.atan2(dy,dx);
    //calculate the difference between current touch values and the start values
    var scalePixelChange = touchDistance - input.touchStartDistance;
    var angleChange = touchAngle - input.touchStartAngle;
    //calculate how much this should affect the actual object
    currentScale = input.startScale + scalePixelChange*0.01;
    currentRotation = input.startAngle+(angleChange*180/Math.PI);
    //upper and lower limit of scaling
    if(currentScale<0.5) currentScale = 0.5;
    if(currentScale>3) currentScale = 3;
  }
}

हर टचमूव इवेंट के बीच की दूरी में होने वाले बदलाव का इस्तेमाल, खींचकर छोड़ने के उदाहरण की तरह ही किया जा सकता है. हालांकि, यह तरीका अक्सर तब ज़्यादा काम आता है, जब आपको लगातार मूवमेंट चाहिए.

function onAnimationFrame() {
  requestAnimationFrame( onAnimationFrame );
  //execute transform based on currentScale and currentRotation
  /*
  /
  */

  //because touchmove is only fired when finger is actually moving we need to reset the delta values each frame
  input.dragDX=0;
  input.dragDY=0;
}

अगर आप चाहें, तो पिंच करके और घुमाने के लिए जेस्चर का इस्तेमाल करते समय ऑब्जेक्ट को खींचकर छोड़ने की सुविधा भी चालू की जा सकती है. इस स्थिति में, आप दो उंगलियों के बीच केंद्र बिंदु का इस्तेमाल, खींचने वाले हैंडलर के इनपुट के तौर पर करेंगे.

एम्बेड किए गए उदाहरण: किसी ऑब्जेक्ट को 2D में घुमाना और स्केल करना. Explore में मैप को लागू करने के तरीके के जैसा: http://cdpn.io/izloq

एक ही हार्डवेयर पर माउस और टच सहायता

आज Chromebook Pixel जैसे कई लैपटॉप कंप्यूटर उपलब्ध हैं, जो माउस और टच इनपुट, दोनों का समर्थन करते हैं. अगर आप सावधानी नहीं बरतते हैं, तो इसकी वजह से कुछ अनचाहे व्यवहार हो सकते हैं.

एक ज़रूरी बात यह है कि आपको सिर्फ़ टच सपोर्ट का पता लगाकर माउस इनपुट को अनदेखा करना चाहिए, बल्कि एक साथ दोनों काम करने चाहिए.

अगर आप अपने टच इवेंट हैंडलर में event.preventDefault() का इस्तेमाल नहीं कर रहे हैं, तो कुछ एम्युलेट किए गए माउस इवेंट भी ट्रिगर होंगे. इससे ज़्यादातर नॉन-टच ऑप्टिमाइज़ की गई साइटें काम करती रहेंगी. उदाहरण के लिए, स्क्रीन पर एक बार टैप करने पर ये इवेंट तेज़ क्रम में और इस क्रम में फ़ायर हो सकते हैं:

  1. टचस्टार्ट
  2. टचमूव
  3. टचएंड
  4. mouseover
  5. mousemove
  6. mousedown
  7. माउसअप
  8. क्लिक

अगर आपके इंटरैक्शन थोड़े ज़्यादा जटिल होते हैं, तो माउस इवेंट की वजह से कुछ अनचाहे व्यवहार हो सकते हैं और आपका इंप्लीमेंटेशन खराब हो सकता है. टच इवेंट हैंडलर में event.preventDefault() का इस्तेमाल करना और अलग-अलग इवेंट हैंडलर में माउस इनपुट को मैनेज करना अक्सर सबसे अच्छा होता है. आपको यह ध्यान रखना होगा कि टच इवेंट हैंडलर में event.preventDefault() का इस्तेमाल करने पर, कुछ डिफ़ॉल्ट कार्रवाइयां नहीं की जा सकेंगी. जैसे, स्क्रोल करना और क्लिक इवेंट.

" Build with Chrome में हम नहीं चाहते कि जब कोई व्यक्ति साइट पर दो बार टैप करे, तो ज़ूमिंग न हो. हालांकि, ज़्यादातर ब्राउज़र में यह सुविधा स्टैंडर्ड फ़ॉर्मैट में होती है. इसलिए, जब कोई उपयोगकर्ता दो बार टैप करता है, तो ब्राउज़र को ज़ूम न करने के लिए कहने के लिए हम व्यूपोर्ट मेटा टैग का इस्तेमाल करते हैं. यह 300 मि॰से॰ क्लिक की देरी को भी हटा देता है, जिससे साइट का रिस्पॉन्स बेहतर होता है. (डबल-टैप ज़ूमिंग चालू होने पर एक टैप और डबल टैप के बीच अंतर करने के लिए क्लिक में देरी होती है.)

<meta name="viewport" content="width=device-width,user-scalable=no">

याद रखें कि इस सुविधा का इस्तेमाल करते समय, साइट को सभी स्क्रीन साइज़ पर पढ़ने लायक बनाना आपके ऊपर है, क्योंकि उपयोगकर्ता ज़ूम नहीं कर पाएगा.

माउस, टच, और कीबोर्ड इनपुट

'एक्सप्लोर 3D मोड' में हम चाहते थे कि मैप पर नेविगेट करने के तीन तरीके हों: माउस (खींचना), टच करना (खींचना, ज़ूम करने और घुमाने के लिए पिंच करना) और कीबोर्ड (ऐरो बटन से नेविगेट करना). नेविगेशन के ये सभी तरीके थोड़े अलग तरीके से काम करते हैं, लेकिन हमने सभी के लिए एक ही तरीके का इस्तेमाल किया है. इवेंट हैंडलर में वैरिएबल सेट करके, requestAnimationFrame लूप में काम किया जाता है. requestAnimationFrame लूप में नेविगेट करने के लिए, यह जानना ज़रूरी नहीं होता कि कौनसा तरीका इस्तेमाल किया गया है.

उदाहरण के तौर पर, हम इनपुट के तीनों तरीकों का इस्तेमाल करके, मैप की मूवमेंट (ड्रैगडीX और DragDY) को सेट कर सकते हैं. यहां कीबोर्ड लागू करने का तरीका बताया गया है:

document.addEventListener('keydown', onKeyDown );
document.addEventListener('keyup', onKeyUp );

function onKeyDown( event ) {
  input.keyCodes[ "k" + event.keyCode ] = true;
  input.shiftKey = event.shiftKey;
}

function onKeyUp( event ) {
  input.keyCodes[ "k" + event.keyCode ] = false;
  input.shiftKey = event.shiftKey;
}

//this needs to be called every frame before animation is executed
function handleKeyInput(){
  if(input.keyCodes.k37){
    input.dragDX = -5; //37 arrow left
  } else if(input.keyCodes.k39){
    input.dragDX = 5; //39 arrow right
  }
  if(input.keyCodes.k38){
    input.dragDY = -5; //38 arrow up
  } else if(input.keyCodes.k40){
    input.dragDY = 5; //40 arrow down
  }
}

function onAnimationFrame() {
  requestAnimationFrame( onAnimationFrame );
  //because keydown events are not fired every frame we need to process the keyboard state first
  handleKeyInput();
  //implement animations based on what is stored in input
   /*
  /
  */

  //because touchmove is only fired when finger is actually moving we need to reset the delta values each frame
  input.dragDX = 0;
  input.dragDY = 0;
}

एम्बेड किए गए उदाहरण: नेविगेट करने के लिए माउस, टच, और कीबोर्ड का इस्तेमाल करना: http://cdpn.io/catlf

खास जानकारी

कई अलग-अलग स्क्रीन साइज़ वाले टच डिवाइसों के साथ काम करने के लिए, Build with Chrome को अपने हिसाब से इस्तेमाल करना काफ़ी फ़ायदेमंद रहा है. टीम के पास टच डिवाइसों पर इस तरह की इंटरैक्टिविटी का बहुत ज़्यादा अनुभव नहीं था और इस दौरान हमने बहुत कुछ सीखा.

सबसे बड़ी चुनौती यह थी कि उपयोगकर्ता अनुभव और डिज़ाइन को कैसे हल किया जाए. तकनीकी चुनौतियां कई स्क्रीन साइज़, टच इवेंट, और परफ़ॉर्मेंस से जुड़ी समस्याओं को मैनेज करना था.

हालांकि, टच डिवाइसों पर WebGL शेडर के साथ कुछ समस्याएं आ रही थीं, लेकिन यह कुछ ऐसा है जो उम्मीद से बेहतर तरीके से काम करता है. डिवाइस ज़्यादा से ज़्यादा ताकतवर होते जा रहे हैं. साथ ही, WebGL के काम करने के तरीके तेज़ी से बेहतर हो रहे हैं. हमें लगता है कि हम आने वाले समय में डिवाइसों पर WebGL का और भी इस्तेमाल करेंगे.

अगर आपने अभी तक ऐसा नहीं किया है, तो अब कुछ शानदार बनाएं!