Chrome ile geliştirin

LEGO® tuğlaları Çok Cihazlı Web'e taşınıyor

Hans Eklund
Hans Eklund

İlk olarak Avustralya'da kullanıma sunulan masaüstü Chrome kullanıcıları için eğlenceli bir deney olan Build with Chrome'u 2014'te piyasaya sürmüştük. Bu denemede dünya geneli kullanılabilirlik, THE LEGO® MovieTM ile bağlantılı özellikler ve mobil cihazlar için yeni destek sunulmaktaydı. Bu makalede, projeden, özellikle de yalnızca masaüstü deneyiminden hem fare hem de dokunmatik girişi destekleyen birden çok ekranlı bir çözüme geçişle ilgili bazı öğrendiklerimizi paylaşacağız.

Build with Chrome'un Geçmişi

Build with Chrome'un ilk sürümü Avustralya'da 2012'de kullanıma sunuldu. Web'in gücünü yepyeni bir şekilde göstermek ve Chrome'u yepyeni bir kitleye sunmak istedik.

Sitenin iki ana bölümü vardı: Kullanıcıların LEGO tuğlaları kullanarak yapılar oluşturabileceği "Yapı" modu ve Google Haritalar'ın LEGO yapımı bir sürümünde ortaya çıkan eserlere göz atmak için "Keşfet" modu.

Kullanıcılara en iyi LEGO inşa deneyimini sunmak için etkileşimli 3B çok önemliydi. 2012 yılında WebGL yalnızca masaüstü tarayıcılarda kullanılabildiğinden, Build yalnızca masaüstü bilgisayarlara yönelik bir deneyim olarak hedeflendi. Explore, eserleri görüntülemek için Google Haritalar'ı kullandı ancak yeterince yakınlaştığında, yapımları 3D olarak gösteren haritanın WebGL uygulamasına geçiş yaptı. Ancak, yine de temel plaka dokusu olarak Google Haritalar'ı kullanıyordu. Her yaştan LEGO tutkunlarının yaratıcılıklarını kolayca ve sezgisel olarak ifade edebilecekleri ve birbirlerinin eserlerini keşfedebilecekleri bir ortam oluşturmayı umuyorduk.

2013'te, Build with Chrome'u yeni web teknolojileriyle genişletmeye karar verdik. Bu teknolojilerden biri de Android için Chrome'da geliştirilen WebGL oldu. Bu teknoloji, doğal olarak Build with Chrome'un mobil deneyime dönüşmesini sağlayacaktı. Başlangıç olarak, "Builder Tool"un donanımını sorgulamadan önce dokunma prototiplerini geliştirdik. Bu şekilde, bir mobil uygulamaya kıyasla bir tarayıcıda karşılaşabileceğimiz hareket davranışını ve dokunma duyarlılığını anladık.

Duyarlı Kullanıcı Arabirimi

Hem dokunmatik hem de fare girişi olan cihazları desteklememiz gerekiyordu. Ancak, küçük dokunmatik ekranlarda aynı kullanıcı arayüzünün kullanılması, alan kısıtlamaları nedeniyle yetersiz bir çözüm olarak ortaya çıktı.

Build'da çok fazla etkileşim gerçekleşir: yakınlaştırma ve uzaklaştırma, tuğla renklerini değiştirme ve elbette tuğlaları seçme, döndürme ve yerleştirme. Kullanıcıların sıklıkla çok fazla zaman geçirdiği bir araç olduğundan, sık kullandıkları her şeye hızlı bir şekilde erişebilmeleri ve bununla rahatça etkileşim kurmaları önemlidir.

Yüksek düzeyde etkileşimli dokunma uygulaması tasarlarken ekranın hızlı bir şekilde küçük olduğunu ve kullanıcının parmaklarının etkileşim sırasında ekranın büyük bir kısmını kapladığını fark edersiniz. İnşaatçı ile çalışırken bu durumu açıkça görmüştük. Tasarımı yaparken grafiklerdeki piksellerden ziyade fiziksel ekran boyutunu göz önünde bulundurmalısınız. Asıl içeriğe ayrılmış mümkün olduğunca fazla ekran alanı elde etmek için düğme ve denetim sayısını en aza indirmek önemli hale gelir.

Amacımız, Build'ı dokunmatik cihazlarda doğal hale getirmek, orijinal masaüstü uygulamasına dokunmatik giriş eklemekle kalmayıp aynı zamanda dokunmaya yönelik tasarlanmış hissi uyandırmaktı. Kullanıcı arayüzünün, biri büyük ekranlı masaüstü bilgisayarlar ve tabletler, diğeri ise daha küçük ekranlı mobil cihazlar için olmak üzere iki varyasyonu elde ettik. Mümkün olduğunda tek bir uygulama kullanmak ve modlar arasında akıcı bir geçiş sağlamak en iyisidir. Bizim örneğimizde, bu iki mod arasında deneyim açısından önemli bir fark olduğunu belirledik ve bu nedenle belirli bir ayrılma noktasına güvenmeye karar verdik. Bu iki sürümde birçok ortak özellik bulunuyor. Çoğu şeyi tek bir kod uygulamasıyla yapmaya çalıştık; ancak kullanıcı arayüzünün bazı yönleri bu iki sürüm arasında farklı şekilde çalışıyor.

Mobil cihazları algılamak için kullanıcı aracısı verilerini kullanırız ve ardından, küçük ekranlı mobil kullanıcı arayüzünün kullanılıp kullanılmayacağına karar vermek için görüntü alanı boyutunu kontrol ederiz. "Büyük ekran" için bir ayrılma noktası seçmek biraz zordur, çünkü fiziksel ekran boyutu için güvenilir bir değer elde etmek zordur. Neyse ki bizim örneğimizde, küçük ekranlı kullanıcı arayüzünü büyük ekranlı bir dokunmatik cihazda göstermemizin gerçekten bir önemi yok. Çünkü araç yine iyi bir şekilde çalışacağından, sadece bazı düğmeler biraz fazla büyük görünebilir. Sonunda, ayrılma noktasını 1000 piksele ayarlarız; siteyi 1000 pikselden daha geniş bir pencereden (yatay modda) yüklerseniz büyük ekran sürümünü elde edersiniz.

Şimdi iki ekran boyutundan ve deneyiminden bahsedelim:

Büyük ekran, fare ve dokunma desteği

Büyük ekran sürümü, fare desteği olan tüm masaüstü bilgisayarlarda ve büyük ekranlı dokunmatik cihazlarda (Google Nexus 10 gibi) sunulur. Bu sürüm, ne tür gezinme denetimlerinin mevcut olduğu konusunda orijinal masaüstü çözümüne yakındır, ancak dokunma desteği ve bazı hareketler ekledik. Kullanıcı arayüzünü pencere boyutuna bağlı olarak ayarlarız. Dolayısıyla, kullanıcı pencereyi yeniden boyutlandırdığında, kullanıcı arayüzünün bir kısmını kaldırabilir veya yeniden boyutlandırabilir. Bunu CSS medya sorguları kullanarak yaparız.

Örnek: Kullanılabilir yükseklik 730 pikselden az olduğunda Keşif modundaki yakınlaştırma kaydırma çubuğu kontrolü gizlenir:

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

Küçük ekran, sadece dokunmatik destek

Bu sürüm, mobil cihazlarda ve küçük tabletlerde (hedef cihazlar Nexus 4 ve Nexus 7) yayınlanır. Bu sürüm için çoklu dokunma desteği gerekiyor.

Küçük ekranlı cihazlarda, içeriğe mümkün olduğunca çok ekran alanı sağlamamız gerekir. Bu nedenle, alanı maksimuma çıkarmak için, çoğunlukla nadiren kullanılmayan öğeleri gözden uzaklaştırarak birkaç ince ayar yaptık:

  • Yapı tuğlası seçici, yapı sırasında bir renk seçicinin simge durumuna küçültülür.
  • Yakınlaştırma ve yön kontrollerini, çoklu dokunma hareketleriyle değiştirdik.
  • Chrome'un tam ekran işlevi de fazladan ekran alanı elde etmek açısından yararlı olur.
Büyük ekranda oluşturun
Büyük ekranda oluşturun. Tuğla seçici her zaman görünür durumda ve sağ tarafta birkaç kontrol bulunuyor.
Küçük ekranda oluşturun
Küçük bir ekranda uygulama yapın. Tuğla seçici küçültülmüş ve bazı düğmeler kaldırılmıştır.

WebGL Performansı ve Desteği

Modern dokunmatik cihazlar oldukça güçlü GPU'lara sahiptir ancak yine de masaüstü muadillerinden uzakta olduğundan, performans konusunda bazı zorluklarla karşılaşacağımızı biliyorduk. Özellikle de aynı anda birçok şeyi aynı anda oluşturmamız gereken 3D Keşfedin modunda zorlanıyorduk.

Yaratıcı bir şekilde, karmaşık şekillere, hatta şeffaflığa sahip, genellikle GPU'ya çok fazla ağırlık veren özellikler içeren birkaç yeni tuğla türü eklemek istedik. Ancak geriye dönük uyumlu olmamız ve ilk sürümdeki yapımları desteklemeye devam etmemiz gerekiyordu. Bu nedenle, yapımlardaki toplam tuğla sayısını önemli ölçüde azaltmak gibi yeni kısıtlamalar belirleyemedik.

Build'ın ilk sürümünde tek bir yapıda kullanılabilecek maksimum tuğla sınırımız vardı. Kalan tuğla sayısını gösteren bir "tuğla ölçer" bulunuyordu. Yeni uygulamada, tuğla sayacını standart tuğlalardan daha fazla etkileyecek ve böylece toplam maksimum tuğla sayısını biraz azaltacak yeni tuğlalardan bir kısmını yaptık. Bu, iyi bir performansı sürdürürken yeni tuğlaları dahil etmenin bir yoluydu.

3D Keşfet modunda, aynı anda birçok işlem gerçekleşir: Taban plaka dokularının yüklenmesi, yapımların yüklenmesi, canlandırma ve oluşturulması vb. Bu işlem hem GPU hem de CPU için çok fazla işlem gerektirdiğinden, bu bölümleri mümkün olduğunca optimize etmek için Chrome Geliştirici Araçları'nda çok sayıda çerçeve profili oluşturma işlemi gerçekleştirdik. Aynı anda çok fazla yapım oluşturmak zorunda kalmamak için mobil cihazlarda yapımlara biraz daha yakınlaştırmaya karar verdik.

Bazı cihazlar, bazı WebGL gölgelendiricilerini yeniden ziyaret etmemizi ve basitleştirmemizi sağladı, ancak her zaman bunu çözmenin ve ilerlemenin bir yolunu bulduk.

WebGL olmayan cihazları destekleme

Ziyaretçinin cihazı WebGL'yi desteklemese bile sitenin bir şekilde kullanılabilir olmasını istedik. Bazen bir tuval çözümü veya CSS3D özellikleri kullanarak 3D'yi basitleştirilmiş bir şekilde göstermenin yolları vardır. Maalesef, WebGL'yi kullanmadan Derleme ve Keşfetme 3D özelliklerini çoğaltmaya yetecek kadar iyi bir çözüm bulamadık.

Tutarlılık için, yapımların görsel stili tüm platformlarda aynı olmalıdır. 2.5D çözümüyle ilgili çaba sarf edebilirdik ancak bu şekilde oluşturulan yapımlar bazı açılardan farklı görünebilirdi. Ayrıca Build with Chrome'un ilk sürümüyle oluşturulan yapımların sitenin yeni sürümünde de olduğu gibi görünmesini ve sorunsuz çalışmasını nasıl sağlayacağımızı düşünmemiz gerekiyordu.

Yeni yapımlar oluşturamıyor veya 3D olarak keşfedemeseniz bile, 2D Modunu Keşfet dışındaki cihazlar tarafından erişilebilir. Böylece kullanıcılar, WebGL etkin bir cihaz kullanıyor olsalar dahi projenin derinliği ve bu aracı kullanarak ne yaratabilecekleri hakkında bir fikir edinebilirler. Site, WebGL desteği olmayan kullanıcılar için değerli olmayabilir, ancak en azından bir teaser görevi görmeli ve onu denemeye katılmalarını sağlamalıdır.

WebGL çözümleri için yedek sürümleri saklamak bazen mümkün olmayabilir. Bunun birçok olası nedeni vardır: performans, görsel stil, geliştirme ve bakım maliyetleri vb. Bununla birlikte, bir yedek uygulamamaya karar verdiğinizde, en azından WebGL'yi kullanmayan ziyaretçilerle ilgilenmeli, neden siteye tam olarak erişemediğini açıklamalı ve WebGL'yi destekleyen bir tarayıcı kullanarak sorunu nasıl çözebileceklerine ilişkin talimatlar vermelisiniz.

Varlık Yönetimi

2013'te Google, Google Haritalar'ın yeni sürümünü kullanıma sundu. Bu sürüm kullanıma sunulduğundan beri kullanıcı arayüzüyle ilgili en önemli değişiklikler yapıldı. Bu nedenle, Build with Chrome'u yeni Google Haritalar kullanıcı arayüzüne uyacak şekilde yeniden tasarlamaya karar verdik ve bunu yaparken, yeni tasarımın diğer faktörlerini hesaba kattık. Yeni tasarım, net renkler ve basit şekillerle nispeten düz bir yapıya sahip. Bu, çok sayıda kullanıcı arayüzü öğesinde CSS kullanmamızı sağlayarak resim kullanımını en aza indirmemizi sağladı.

Keşfedin'de çok sayıda resim yüklememiz gerekiyor. Yapımlar için küçük resimler, taban plakaları için harita dokuları ve son olarak da gerçek 3D yapılar. Sürekli yeni resimler yüklerken bellek sızıntısı olmaması için ekstra özen gösteriyoruz.

3D yapımlar PNG resim olarak paketlenmiş özel bir dosya biçiminde depolanır. 3D yapımlarla ilgili verilerin görüntü olarak saklanması, verileri temel olarak, yapımları oluşturan gölgelendiricilere doğrudan iletmemizi sağladı.

Tasarım, kullanıcı tarafından oluşturulan tüm resimler için tüm platformlarda aynı resim boyutlarını kullanmamızı sağlayarak depolama alanı ve bant genişliği kullanımını en aza indirdi.

Ekran Yönünü Yönetme

Dikey moddan yatay moda geçerken veya ekranın en boy oranının ne kadar değiştiğini kolayca unutabilirsiniz. Mobil cihazlara uyum sağlarken, en baştan bunu göz önünde bulundurmanız gerekir.

Kaydırmanın etkin olduğu geleneksel bir web sitesinde, içeriği ve menüleri yeniden düzenleyen bir duyarlı site elde etmek için CSS kuralları uygulayabilirsiniz. Kaydırma işlevini kullandığınız sürece bu, kolayca yönetilebilir.

Bu yöntemi Build uygulamasında da kullanıyorduk, ancak içeriğin her zaman görünür olması ve hâlâ çok sayıda kontrole ve düğmeye hızlı bir şekilde erişmemiz gerektiğinden düzeni çözme konusunda biraz sınırlıydık. Akış düzeni, haber siteleri gibi salt görüntülü reklam siteleri için çok mantıklı olsa da bizimki gibi bir oyun uygulaması için zorlayıcı bir süreçti. Hem yatay hem dikey yönde çalışan bir düzen bulmak ve aynı zamanda içeriğe dair iyi bir genel bakış ve rahat bir etkileşim biçimi bulmak zor bir iş haline geldi. Sonunda Yapı'yı yalnızca yatay modda tutmaya karar verdik ve kullanıcıya cihazını döndürmesini söyledik.

Keşfet özelliğini çözmek her iki yönde de çok daha kolay oldu. Tutarlı bir deneyim elde etmek için sadece yöne bağlı olarak 3D’nin yakınlaştırma düzeyini ayarlamamız gerekiyordu.

İçerik düzeninin büyük bölümü CSS tarafından kontrol edilir, ancak JavaScript'te uygulanması gereken yönle ilgili bazı şeylerin olması gerekir. Yönü tanımlamak için window.orientation özelliğinin kullanıldığı iyi bir cihazlar arası çözüm bulunamadı. Sonuç olarak, cihazın yönünü belirlemek için yalnızca window.innerWidth ve window.innerHeight öğelerini karşılaştırdık.

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

Dokunma Desteği Ekleme

Web içeriğine dokunma desteği eklemek oldukça basit bir işlemdir. Tıklama etkinliği gibi temel etkileşim özellikleri, masaüstü bilgisayarlarda ve dokunmatik cihazlarda aynı şekilde çalışır. Ancak daha ileri düzey etkileşimler söz konusu olduğunda dokunma etkinliklerini de yönetmeniz gerekir: Dokunmayla başlatma, dokunarak taşıma ve dokunma. Bu makalede, bu etkinliklerin nasıl kullanılacağıyla ilgili temel bilgiler yer almaktadır. Internet Explorer dokunma etkinliklerini desteklemez, bunun yerine İşaretçi Etkinlikleri'ni (işaretçi indirme, işaretçi taşıma, işaretçi yukarı) kullanır. İşaretçi Etkinlikleri standartlaştırma için W3C'ye gönderildi ancak şimdilik yalnızca Internet Explorer'da uygulanmaktadır.

3D Keşfet modunda, standart Google Haritalar uygulamasıyla aynı gezinme deneyimini kullanmak istiyorduk. Bir parmağınızı haritayı kaydırmak ve yakınlaştırmak için iki parmağınızı birbirine yaklaştırmak istiyorduk. Yapımlar 3D olduğundan iki parmakla döndürme hareketini de ekledik. Bu, genellikle dokunma etkinliklerinin kullanılmasını gerektiren bir şeydir.

Etkinlik işleyicilerde 3D'yi güncelleme veya oluşturma gibi yoğun işlem işlemlerinden kaçınmak iyi bir uygulamadır. Bunun yerine, dokunmatik girişi bir değişkende depolayın ve requestAnimationFrame oluşturma döngüsündeki girişe tepki verin. Bu, aynı anda fare uygulamasını da kolaylaştırır. Karşılık gelen fare değerlerini aynı değişkenlerde depolamanız yeterlidir.

Girişi depolamak için bir nesneyi başlatarak başlayın ve touchstart etkinlik işleyiciyi ekleyin. Her etkinlik işleyicide event.preventDefault() adını veririz. Bunun amacı, tarayıcının dokunma etkinliğini işlemeye devam etmesini engellemektir. Bu etkinlik, sayfanın kaydırılması veya sayfanın tamamını ölçeklendirmek gibi beklenmedik davranışlara neden olabilir.

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

Girişin gerçek depolamasını etkinlik işleyicilerde değil, ayrı işleyicilerde gerçekleştiriyoruz: HandleDragStart,HandleDragging veHandleDragStop. Çünkü bu öğeleri fare etkinlik işleyicilerinden de çağırabilmek istiyoruz. Çok düşük bir ihtimal olsa da kullanıcının aynı anda dokunma ve fareyi kullanabileceğini unutmayın. Bu durumla doğrudan ilgilenmek yerine, videoda herhangi bir patlama yaşanmamasını sağlıyoruz.

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

Dokunarak taşımaya dayalı animasyonlar yaparken, son etkinlikten sonraki delta hareketini de kaydetmek çoğu zaman yararlıdır. Örneğin, bunu Keşfet'teki tüm taban plakalar üzerinde hareket ettirirken kameranın hızı için bir parametre olarak kullandık. Bunun nedeni, taban plakaları sürüklememeniz, bunun yerine kamerayı hareket ettirmenizdir.

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

Yerleşik örnek: Dokunma etkinliklerini kullanarak bir nesneyi sürükleme. Build with Chrome'da 3D Keşfet haritasını sürükleyip bırakmaya benzer bir uygulama: http://cdpn.io/qDxvo

Çoklu Dokunma Hareketleri

Çoklu dokunma hareketlerinin yönetimini basitleştirmeyi sağlayan Hammer veya QuoJS gibi çeşitli çerçeveler veya kitaplıklar vardır. Ancak birden fazla hareketi birleştirmek ve tam kontrol elde etmek istiyorsanız bazen en iyi yöntem sıfırdan başlamaktır.

Sıkıştırma ve döndürme hareketlerini yönetmek için, ikinci parmak ekrana koyulduğunda iki parmak arasındaki mesafeyi ve açıyı kaydederiz:

//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;
}

Dokunarak taşıma etkinliğinde, daha sonra bu iki parmak arasındaki mesafe ve açı sürekli olarak ölçülür. Başlangıç mesafesi ile geçerli mesafe arasındaki fark daha sonra ölçeği ayarlamak için kullanılır ve başlangıç açısı ile mevcut açı arasındaki fark da açıyı ayarlamak için kullanılır.

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

Her dokunarak taşıma etkinliği arasındaki mesafe değişikliğini, sürükleme örneğindekine benzer bir şekilde potansiyel olarak kullanabilirsiniz, ancak sürekli bir hareket istediğinizde bu yaklaşım çoğu zaman daha yararlıdır.

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

İsterseniz, sıkıştırma ve döndürme hareketlerini yaparken nesnenin sürüklenmesini de etkinleştirebilirsiniz. Bu durumda, iki parmak arasındaki merkez noktasını sürükleme işleyiciye giriş olarak kullanırsınız.

Yerleşik örnek: Bir nesneyi 2D olarak döndürme ve ölçeklendirme. Keşfet'teki haritanın uygulanmasına benzer: http://cdpn.io/izloq

Aynı Donanımda Fare ve Dokunma Desteği

Bugün Chromebook Pixel gibi hem fare hem de dokunmatik girişi destekleyen birkaç dizüstü bilgisayar var. Bu, dikkatli olmazsanız bazı beklenmeyen davranışlara neden olabilir.

Önemli noktalardan biri, sadece dokunma desteğini algılayıp ardından fare girişini yoksayıp aynı anda her ikisini de desteklemektir.

Dokunma etkinliği işleyicilerinizde event.preventDefault() kullanmıyorsanız, dokunma işlemi için optimize edilmiş sitelerin çoğunun çalışmaya devam etmesi için bazı emüle edilmiş fare etkinlikleri de tetiklenecektir. Örneğin, ekrana bir kez dokunduğunuzda, bu etkinlikler hızlı bir şekilde ve şu sırayla tetiklenebilir:

  1. dokunma başlangıcı
  2. Touchmove
  3. dokunmatik uç
  4. fareyle üzerine gelme
  5. mousemove
  6. fareyi aşağı çekme
  7. fareyi yukarı çekme
  8. click

Biraz daha karmaşık etkileşimleriniz varsa bu fare etkinlikleri bazı beklenmeyen davranışlara neden olabilir ve uygulamanızı bozabilir. Dokunma etkinlik işleyicilerinde event.preventDefault() kullanmak ve fare girişini ayrı etkinlik işleyicilerde yönetmek genellikle en iyisidir. Dokunmatik etkinlik işleyicilerde event.preventDefault() kullanmanın, kaydırma ve tıklama etkinliği gibi bazı varsayılan davranışları da engelleyeceğini unutmayın.

"Build with Chrome'da çoğu tarayıcıda standart olmasına rağmen, bir kişi siteye iki kez dokunduğunda yakınlaştırma/uzaklaştırma yapılmasını istemedik. Bu nedenle, bir kullanıcı iki kez dokunduğunda tarayıcıya yakınlaştırma yapmamasını söylemek için görüntü alanı meta etiketini kullanırız. Bu işlem aynı zamanda 300 ms'lik tıklama gecikmesini de ortadan kaldırarak sitenin duyarlılığını iyileştirir. (İki kez dokunarak yakınlaştırma etkinken yapılan tıklama gecikmesi, bir kez dokunma ile iki kez dokunma arasındaki farkı birbirinden ayırmak için vardır.)

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

Bu özelliği kullanırken sitenin tüm ekran boyutlarında okunabilir olmasını sağlamanın size bağlı olduğunu unutmayın. Çünkü kullanıcı yakınlaştırma yapamaz.

Fare, Dokunma ve Klavye Girişi

3D Keşfet modunda, haritada gezinmek için üç yol olmasını istiyorduk: fare (sürükleme), dokunma (sürükleme, yakınlaştırmak ve döndürmek için sıkıştırma) ve klavye (ok tuşlarıyla gezinme). Bu gezinme yöntemlerinin tümü biraz farklı çalışır, ancak hepsinde aynı yaklaşımı kullandık: Etkinlik işleyicilerde değişkenleri ayarlama ve requestAnimationFrame döngüsünde buna göre hareket etme. requestAnimationFrame döngüsünün gezinmek için hangi yöntemin kullanıldığını bilmesi gerekmez.

Örneğin, haritanın hareketini (dragDX ve dragDY) üç giriş yöntemiyle de ayarlayabiliriz. Klavye uygulaması şu şekildedir:

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

Yerleşik örnek: Gezinmek için fare, dokunma ve klavye kullanma: http://cdpn.io/catlf

Özet

Build with Chrome'u pek çok farklı ekran boyutuna sahip dokunmatik cihazları destekleyecek şekilde uyarlamak bir öğrenim deneyimi oldu. Ekip, dokunmatik cihazlarda bu düzeyde etkileşim yapma konusunda çok fazla deneyime sahip değildi ve yol boyunca çok şey öğrendik.

En büyük zorluk, kullanıcı deneyimi ve tasarımının nasıl çözüleceğiydi. Birçok ekran boyutu, dokunma etkinliği ve performans sorununu yönetmeyle ilgili teknik sorunlar yaşanıyordu.

Dokunmatik cihazlarda WebGL gölgelendiricileriyle ilgili bazı zorluklar olsa da bu, neredeyse beklenenden daha iyi sonuç veren bir çözüm oldu. Cihazlar giderek daha güçlü hale geliyor ve WebGL uygulamaları hızla iyileşiyor. Yakın gelecekte cihazlarda WebGL'yi çok daha fazla kullanacağımızı düşünüyoruz.

Henüz yapmadıysanız mükemmel bir şey geliştirin!