Xây dựng với Chrome

Mang khối hình LEGO® lên web đa thiết bị

Hans Eklund
Hans Eklund

Xây dựng với Chrome, một thử nghiệm thú vị cho người dùng Chrome dành cho máy tính để bàn được phát hành lần đầu tại Úc, đã được phát hành lại vào năm 2014 với tính sẵn có trên toàn cầu, mối liên hệ với THE LEGO® MOVIETM và tính năng hỗ trợ mới được bổ sung cho thiết bị di động. Trong bài viết này, chúng tôi sẽ chia sẻ một số bài học rút ra được từ dự án này, đặc biệt là về việc chuyển từ trải nghiệm chỉ dành cho máy tính sang giải pháp nhiều màn hình hỗ trợ cả phương thức nhập bằng chuột và bằng cách chạm.

Lịch sử phát triển ứng dụng với Chrome

Phiên bản đầu tiên của ứng dụng Xây dựng bằng Chrome ra mắt tại Úc vào năm 2012. Chúng tôi muốn chứng minh sức mạnh của web theo một cách hoàn toàn mới và mang Chrome đến với đối tượng hoàn toàn mới.

Trang web có hai phần chính: chế độ "Xây dựng" nơi người dùng có thể xây dựng các tác phẩm bằng cách sử dụng các khối hình LEGO và chế độ "Khám phá" để duyệt qua các tác phẩm trên phiên bản Google Maps được phân loại bằng LEGO.

3D tương tác là điều cần thiết để cung cấp cho người dùng trải nghiệm xây dựng LEGO tốt nhất. Trong năm 2012, WebGL chỉ được cung cấp công khai trên trình duyệt dành cho máy tính, vì vậy, tính năng Build đã được nhắm đến dưới dạng trải nghiệm chỉ dành cho máy tính. Khám phá đã sử dụng Google Maps để hiển thị các tác phẩm, nhưng khi phóng to đủ gần, tính năng này chuyển sang triển khai WebGL cho bản đồ hiển thị các tác phẩm ở chế độ 3D, vẫn sử dụng Google Maps làm họa tiết tấm chân đế. Chúng tôi hy vọng sẽ xây dựng được một môi trường nơi những người đam mê LEGO ở mọi lứa tuổi có thể dễ dàng và trực quan thể hiện khả năng sáng tạo của bản thân cũng như khám phá các tác phẩm của nhau.

Năm 2013, chúng tôi quyết định mở rộng ứng dụng Xây dựng với Chrome sang các công nghệ web mới. Trong số các công nghệ đó, có WebGL trong Chrome dành cho Android, một công nghệ tự nhiên sẽ cho phép ứng dụng Xây dựng bằng Chrome phát triển thành trải nghiệm dành cho thiết bị di động. Để bắt đầu, trước tiên chúng tôi đã phát triển các nguyên mẫu cảm ứng trước khi đặt câu hỏi về phần cứng cho "Công cụ tạo bản dựng" nhằm tìm hiểu hành vi cử chỉ và khả năng phản hồi của xúc giác mà chúng tôi có thể gặp phải thông qua trình duyệt so với ứng dụng dành cho thiết bị di động.

Giao diện người dùng thích ứng

Chúng tôi cần hỗ trợ các thiết bị có cả phương thức nhập bằng cách chạm và bằng chuột. Tuy nhiên, việc sử dụng cùng một giao diện người dùng trên các màn hình cảm ứng nhỏ không hẳn là một giải pháp tối ưu do hạn chế về không gian.

Trong Xây dựng có rất nhiều hoạt động tương tác diễn ra: phóng to và thu nhỏ, thay đổi màu khối hình và tất nhiên là chọn, xoay và đặt khối hình. Đó là công cụ mà người dùng thường dành nhiều thời gian, vì vậy điều quan trọng là họ phải có quyền truy cập nhanh vào mọi thứ mà họ sử dụng thường xuyên và họ phải cảm thấy thoải mái khi tương tác với công cụ đó.

Khi thiết kế một ứng dụng cảm ứng có tính tương tác cao, bạn sẽ phát hiện ra rằng màn hình nhanh chóng cho cảm giác nhỏ và ngón tay của người dùng có xu hướng che rất nhiều màn hình trong khi tương tác. Điều này trở nên rõ ràng đối với chúng tôi khi làm việc với Builder. Bạn thực sự phải xem xét kích thước màn hình thực thay vì các điểm ảnh trong đồ hoạ khi thiết kế. Điều quan trọng là phải giảm thiểu số lượng nút và nút điều khiển để có được không gian màn hình rộng nhất có thể dành riêng cho nội dung thực tế.

Mục tiêu của chúng tôi là làm cho ứng dụng Build có cảm giác tự nhiên trên các thiết bị cảm ứng, không chỉ thêm tính năng nhập bằng cách chạm vào triển khai ban đầu trên máy tính để bàn, mà còn tạo cảm giác như nó thực sự dành cho thao tác chạm. Cuối cùng, chúng tôi đã tạo ra hai biến thể của giao diện người dùng, một dành cho máy tính và máy tính bảng có màn hình lớn và một dành cho các thiết bị di động có màn hình nhỏ hơn. Khi có thể, tốt nhất bạn nên sử dụng một phương pháp triển khai duy nhất và chuyển đổi linh hoạt giữa các chế độ. Trong trường hợp này, chúng tôi xác định rằng có sự khác biệt đáng kể về trải nghiệm giữa hai chế độ này đến mức chúng tôi quyết định dựa vào một điểm ngắt cụ thể. Hai phiên bản này có rất nhiều tính năng chung và chúng tôi đã cố gắng thực hiện hầu hết mọi việc chỉ bằng một lần triển khai mã. Tuy nhiên, một số khía cạnh của giao diện người dùng hoạt động khác nhau giữa hai phiên bản.

Chúng ta sử dụng dữ liệu tác nhân người dùng để phát hiện thiết bị di động, sau đó kiểm tra kích thước khung nhìn để quyết định xem có nên sử dụng giao diện người dùng dành cho thiết bị di động màn hình nhỏ hay không. Hơi khó để chọn điểm ngắt cho phù hợp với "màn hình lớn", vì rất khó để có được giá trị đáng tin cậy của kích thước màn hình thực. May mắn là trong trường hợp của chúng ta, việc hiển thị giao diện người dùng màn hình nhỏ trên thiết bị cảm ứng có màn hình lớn sẽ không gây ảnh hưởng gì, vì công cụ này vẫn hoạt động tốt, chỉ là một số nút có thể cảm thấy quá lớn. Cuối cùng, chúng ta đặt điểm ngắt thành 1000 pixel; nếu tải trang web từ cửa sổ rộng hơn 1000 pixel (ở chế độ ngang), bạn sẽ nhận được phiên bản cho màn hình lớn.

Hãy nói một chút về hai kích thước màn hình và trải nghiệm hai kích thước màn hình này:

Màn hình lớn, có hỗ trợ chuột và cảm ứng

Phiên bản màn hình lớn được phân phối cho tất cả máy tính có hỗ trợ chuột và cho thiết bị cảm ứng có màn hình lớn (chẳng hạn như Google Nexus 10). Phiên bản này gần giống với giải pháp ban đầu dành cho máy tính để bàn trong các loại điều khiển điều hướng hiện có, nhưng chúng tôi đã thêm hỗ trợ cảm ứng và một số cử chỉ. Chúng ta điều chỉnh giao diện người dùng tuỳ thuộc vào kích thước cửa sổ. Vì vậy, khi người dùng đổi kích thước cửa sổ, thao tác đó có thể xoá hoặc đổi kích thước một số giao diện người dùng. Chúng tôi làm việc này bằng cách sử dụng các truy vấn nội dung nghe nhìn CSS.

Ví dụ: Khi chiều cao có sẵn nhỏ hơn 730 pixel, nút điều khiển thanh trượt thu phóng trong chế độ Khám phá sẽ bị ẩn:

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

Màn hình nhỏ, chỉ hỗ trợ cảm ứng

Phiên bản này được phân phối cho thiết bị di động và máy tính bảng nhỏ (thiết bị mục tiêu Nexus 4 và Nexus 7). Phiên bản này yêu cầu hỗ trợ nhiều điểm chạm.

Trên các thiết bị màn hình nhỏ, chúng ta cần cung cấp cho nội dung nhiều không gian màn hình nhất có thể, vì vậy chúng tôi đã thực hiện một vài điều chỉnh để tối đa hoá không gian, chủ yếu bằng cách di chuyển các yếu tố ít được sử dụng ra khỏi tầm nhìn:

  • Trình chọn khối xây dựng sẽ thu nhỏ thành bộ chọn màu trong khi xây dựng.
  • Chúng tôi đã thay thế các chế độ điều khiển thu phóng và hướng bằng cử chỉ nhiều điểm chạm.
  • Chức năng toàn màn hình của Chrome cũng rất hữu ích để tăng thêm không gian màn hình.
Xây dựng trên màn hình lớn
Tạo ứng dụng trên màn hình lớn. Trình chọn khối luôn hiển thị và có một vài nút điều khiển ở bên phải.
Tạo ứng dụng trên màn hình nhỏ
Tạo ứng dụng trên màn hình nhỏ. Trình chọn khối đã được thu nhỏ và một số nút đã bị xoá.

Hiệu suất và hỗ trợ WebGL

Các thiết bị cảm ứng hiện đại có GPU khá mạnh, nhưng vẫn khác xa so với máy tính để bàn, vì vậy, chúng tôi biết rằng sẽ có một số khó khăn về hiệu suất, đặc biệt là ở chế độ Khám phá 3D, nơi chúng tôi cần kết xuất nhiều tác phẩm cùng lúc.

Một cách sáng tạo, chúng tôi muốn thêm một vài loại khối hình mới có hình dạng phức tạp và thậm chí là trong suốt – những tính năng thường rất nặng trên GPU. Tuy nhiên, chúng tôi phải có khả năng tương thích ngược và tiếp tục hỗ trợ các tác phẩm từ phiên bản đầu tiên, vì vậy chúng tôi không thể đặt bất kỳ hạn chế mới nào, chẳng hạn như giảm đáng kể tổng số khối hình trong tác phẩm.

Trong phiên bản đầu tiên của ứng dụng Xây dựng, chúng tôi đã giới hạn số lượng khối hình tối đa có thể sử dụng trong một lần tạo. Có một "số khối gạch" cho biết có bao nhiêu viên gạch còn lại. Trong quá trình triển khai mới, chúng tôi đã có một số viên gạch mới ảnh hưởng đến số viên gạch nhiều hơn so với viên gạch tiêu chuẩn, do đó làm giảm nhẹ tổng số viên gạch tối đa. Đây là một cách để thêm những khối hình mới trong khi vẫn duy trì hiệu suất tốt.

Trong chế độ Khám phá 3D, có khá nhiều việc xảy ra cùng một lúc; tải hoạ tiết tấm nền, tải tác phẩm, tạo ảnh động và kết xuất tác phẩm, v.v. Việc này đòi hỏi rất nhiều từ cả GPU và CPU, vì vậy, chúng tôi đã thực hiện rất nhiều tạo hồ sơ khung trong Công cụ của Chrome cho nhà phát triển để tối ưu hoá các phần này nhiều nhất có thể. Trên thiết bị di động, chúng tôi quyết định thu phóng gần với tác phẩm hơn một chút để không phải kết xuất nhiều tác phẩm cùng một lúc.

Một số thiết bị yêu cầu chúng tôi truy cập lại và đơn giản hoá một số chương trình đổ bóng WebGL, nhưng chúng tôi luôn tìm ra cách để giải quyết vấn đề này và tiếp tục thực hiện.

Hỗ trợ các thiết bị không phải WebP

Chúng tôi muốn trang web phần nào đó có thể sử dụng được ngay cả khi thiết bị của khách truy cập không hỗ trợ WebGL. Đôi khi, có nhiều cách để thể hiện 3D theo cách đơn giản bằng cách sử dụng giải pháp canvas hoặc các tính năng CSS3D. Rất tiếc, chúng tôi không tìm được giải pháp đủ tốt để sao chép các tính năng Xây dựng và Khám phá 3D mà không sử dụng WebGL.

Để đảm bảo tính nhất quán, phong cách hình ảnh của tác phẩm phải giống nhau trên tất cả các nền tảng. Chúng ta có thể thử giải pháp 2.5D, nhưng điều này sẽ làm cho các tác phẩm trông khác đi theo một cách nào đó. Chúng tôi cũng đã phải xem xét cách đảm bảo các tác phẩm sáng tạo được xây dựng bằng phiên bản đầu tiên của ứng dụng Xây dựng bằng Chrome sẽ trông giống như cũ và chạy mượt mà trong phiên bản mới của trang web như trong phiên bản đầu tiên.

Các thiết bị không phải WebP vẫn có thể truy cập vào chế độ Khám phá 2D, ngay cả khi bạn không thể tạo tác phẩm hoặc khám phá mới ở chế độ 3D. Vì vậy, người dùng vẫn có thể hình dung được chiều sâu của dự án và những gì họ có thể tạo bằng công cụ này nếu họ sử dụng thiết bị hỗ trợ WebGL. Trang web có thể không có giá trị như người dùng không hỗ trợ WebGL, nhưng ít nhất bạn nên dùng trang web này để thử nghiệm.

Đôi khi, việc giữ phiên bản dự phòng cho các giải pháp WebGL là không thể. Có nhiều lý do có thể xảy ra; hiệu suất, kiểu hình ảnh, chi phí phát triển và bảo trì, v.v. Tuy nhiên, khi quyết định không triển khai dự phòng, ít nhất bạn nên chú ý đến khách truy cập chưa bật WebP, giải thích lý do họ không thể truy cập đầy đủ vào trang web và đưa ra hướng dẫn về cách giải quyết vấn đề bằng cách sử dụng trình duyệt hỗ trợ WebGL.

Quản lý tài sản

Vào năm 2013, Google đã giới thiệu một phiên bản mới của Google Maps với các thay đổi giao diện người dùng quan trọng nhất kể từ khi ra mắt. Vì vậy, chúng tôi quyết định thiết kế lại ứng dụng Xây dựng với Chrome cho phù hợp với giao diện người dùng mới của Google Maps và trong quá trình này, chúng tôi đã cân nhắc các yếu tố khác trong thiết kế mới. Thiết kế mới tương đối phẳng với các màu đồng nhất và hình dạng đơn giản. Điều này cho phép chúng tôi sử dụng CSS thuần tuý trên nhiều phần tử giao diện người dùng, giảm thiểu việc sử dụng hình ảnh.

Trong Khám phá, chúng ta cần tải rất nhiều hình ảnh; hình thu nhỏ cho các tác phẩm sáng tạo, ánh xạ hoạ tiết cho các tấm chân đế và cuối cùng là các tác phẩm 3d thực tế. Chúng tôi cẩn trọng hơn để đảm bảo rằng không có tình trạng rò rỉ bộ nhớ khi chúng tôi liên tục tải hình ảnh mới.

Tác phẩm sáng tạo 3D được lưu trữ trong định dạng tệp tùy chỉnh được đóng gói dưới dạng hình ảnh PNG. Việc lưu trữ dữ liệu tác phẩm 3D dưới dạng hình ảnh về cơ bản đã giúp chúng ta truyền dữ liệu trực tiếp đến chương trình đổ bóng để kết xuất tác phẩm đó.

Đối với tất cả hình ảnh do người dùng tạo, thiết kế này cho phép chúng tôi sử dụng cùng một kích thước hình ảnh cho tất cả các nền tảng, do đó giảm thiểu việc sử dụng dung lượng lưu trữ và băng thông.

Quản lý hướng màn hình

Người dùng dễ quên mức độ thay đổi của tỷ lệ khung hình trên màn hình khi chuyển từ chế độ dọc sang chế độ ngang hoặc ngược lại. Bạn cần cân nhắc điều này ngay từ đầu khi điều chỉnh cho phù hợp với thiết bị di động.

Trên trang web truyền thống có bật tính năng cuộn, bạn có thể áp dụng các quy tắc CSS để có được trang web đáp ứng sắp xếp lại nội dung và trình đơn. Miễn là bạn có thể sử dụng chức năng cuộn thì việc này khá dễ quản lý.

Chúng tôi cũng đã sử dụng phương thức này với ứng dụng Xây dựng, nhưng chúng tôi có một chút hạn chế về cách giải quyết bố cục, vì chúng tôi cần hiển thị nội dung mọi lúc, đồng thời vẫn có quyền truy cập nhanh vào một số chế độ điều khiển và nút. Đối với các trang web chứa nội dung đơn thuần như trang web tin tức, bố cục linh hoạt sẽ rất hợp lý, nhưng đối với một ứng dụng trò chơi như ứng dụng của chúng tôi thì đó là một khó khăn. Khó khăn là tìm ra một bố cục phù hợp cả hướng ngang và dọc trong khi vẫn giữ được tổng quan tốt về nội dung và có cách tương tác thoải mái. Cuối cùng, chúng tôi quyết định chỉ xây dựng ứng dụng Xây dựng ở chế độ ngang và yêu cầu người dùng xoay thiết bị.

Khám phá dễ dàng hơn rất nhiều ở cả hai hướng. Chúng ta chỉ cần điều chỉnh mức thu phóng của 3D theo hướng để có được trải nghiệm nhất quán.

Hầu hết bố cục nội dung do CSS kiểm soát, nhưng một số nội dung liên quan đến hướng cần được triển khai trong JavaScript. Chúng tôi nhận thấy rằng không có giải pháp hiệu quả nào trên nhiều thiết bị để sử dụng window.Orientation nhằm xác định hướng, nên cuối cùng, chúng ta chỉ cần so sánh window.innerWidth và window.innerHeight để xác định hướng của thiết bị.

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

Thêm tính năng hỗ trợ cảm ứng

Việc thêm tính năng hỗ trợ cảm ứng vào nội dung trên web khá đơn giản. Hoạt động tương tác cơ bản, chẳng hạn như sự kiện nhấp chuột, hoạt động giống nhau trên máy tính và thiết bị có hỗ trợ cảm ứng. Tuy nhiên, khi nói đến các tương tác nâng cao hơn, bạn cũng cần phải xử lý các sự kiện chạm: khởi động bằng thao tác chạm, di chuyển và chạm. Bài viết này trình bày thông tin cơ bản về cách sử dụng những sự kiện này. Internet Explorer không hỗ trợ các sự kiện chạm mà sử dụng Pointer Sự kiện (pointerdown, pointermove, pointerup). Sự kiện con trỏ đã được gửi đến W3C để tiêu chuẩn hoá nhưng hiện chỉ được triển khai trong Internet Explorer.

Ở chế độ Khám phá 3D, chúng tôi muốn điều hướng giống như khi triển khai Google Maps tiêu chuẩn; sử dụng một ngón tay để xoay quanh bản đồ và chụm hai ngón tay để thu phóng. Vì tác phẩm sáng tạo ở dạng 3D, chúng tôi cũng thêm cử chỉ xoay bằng hai ngón tay. Thông thường, thao tác này sẽ yêu cầu sử dụng sự kiện chạm.

Bạn nên tránh sử dụng máy tính nặng, chẳng hạn như cập nhật hoặc hiển thị mô hình 3D trong trình xử lý sự kiện. Thay vào đó, hãy lưu trữ phương thức nhập bằng cách chạm trong một biến và phản ứng trên giá trị nhập đó trong vòng lặp kết xuất requestAnimationFrame. Điều này cũng giúp việc triển khai bằng chuột đồng thời được dễ dàng hơn, bạn chỉ cần lưu trữ các giá trị chuột tương ứng trong cùng một biến.

Bắt đầu bằng cách khởi tạo một đối tượng để lưu trữ dữ liệu đầu vào và thêm trình nghe sự kiện chạm. Trong mỗi trình xử lý sự kiện, chúng tôi gọi event.ectionDefault(). Việc này nhằm ngăn trình duyệt tiếp tục xử lý sự kiện chạm, từ đó có thể gây ra một số hành vi không mong muốn như cuộn hoặc mở rộng toàn bộ trang.

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

Chúng ta không lưu trữ thực tế dữ liệu đầu vào trong các trình xử lý sự kiện mà thay vào đó là lưu trữ trong các trình xử lý riêng biệt: handleDragStart, handleDragging và handleDragStop. Lý do là vì chúng ta cũng muốn gọi những sự kiện này từ trình xử lý sự kiện chuột. Xin lưu ý rằng mặc dù ít có khả năng xảy ra nhưng người dùng có thể sử dụng thao tác chạm và chuột cùng lúc. Thay vì trực tiếp xử lý trường hợp đó, chúng tôi chỉ đảm bảo không có gì xảy ra.

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

Khi thực hiện ảnh động dựa trên thao tác di chuyển, bạn cũng nên lưu trữ hoạt động di chuyển delta kể từ sự kiện cuối cùng. Ví dụ: chúng tôi sử dụng tham số này làm tham số cho vận tốc của camera khi di chuyển qua tất cả các tấm chân đế trong tính năng Khám phá, vì bạn không kéo các tấm chân đế mà thực sự di chuyển camera.

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

Ví dụ được nhúng: Kéo một đối tượng bằng các sự kiện chạm. Cách triển khai tương tự như khi kéo bản đồ Khám phá 3D trong ứng dụng Xây dựng bằng Chrome: http://cdpn.io/qDxvo

Cử chỉ nhiều điểm chạm

Có một số khung hoặc thư viện, chẳng hạn như Hammer hoặc QuoJS, có thể giúp đơn giản hoá việc quản lý cử chỉ nhiều điểm chạm, nhưng nếu bạn muốn kết hợp nhiều cử chỉ và có toàn quyền kiểm soát, thì đôi khi, bạn nên thực hiện từ đầu.

Để quản lý các cử chỉ chụm và xoay, chúng ta lưu trữ khoảng cách và góc giữa hai ngón tay khi ngón tay thứ hai được đặt trên màn hình:

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

Trong sự kiện di chuyển, chúng ta liên tục đo khoảng cách và góc giữa hai ngón tay đó. Sau đó, hiệu số giữa khoảng cách bắt đầu và khoảng cách hiện tại sẽ được dùng để đặt tỷ lệ và hiệu số giữa góc bắt đầu và góc hiện tại sẽ được dùng để đặt góc.

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

Bạn có thể sử dụng sự thay đổi khoảng cách giữa mỗi sự kiện di chuyển theo cách tương tự như ví dụ về thao tác kéo, nhưng phương pháp đó thường hữu ích hơn khi bạn muốn chuyển động liên tục.

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

Bạn cũng có thể bật tính năng kéo đối tượng trong khi thực hiện cử chỉ chụm và xoay nếu muốn. Trong trường hợp đó, bạn sẽ sử dụng điểm giữa giữa hai ngón tay làm đầu vào cho bộ xử lý kéo.

Ví dụ được nhúng: Xoay và điều chỉnh tỷ lệ đối tượng ở chế độ 2D. Tương tự như cách triển khai bản đồ trong tính năng Khám phá: http://cdpn.io/izloq

Hỗ trợ chuột và cảm ứng trên cùng phần cứng

Ngày nay, có một số máy tính xách tay, chẳng hạn như Chromebook Pixel, hỗ trợ cả phương thức nhập bằng chuột và bằng cách chạm. Điều này có thể gây ra một số hành vi không mong muốn nếu bạn không cẩn thận.

Một điều quan trọng là bạn không nên chỉ phát hiện hỗ trợ cảm ứng rồi bỏ qua thao tác đầu vào bằng chuột, mà thay vào đó, hãy hỗ trợ cả hai cùng một lúc.

Nếu bạn không sử dụng event.preventDefault() trong trình xử lý sự kiện chạm, thì cũng sẽ có một số sự kiện chuột được mô phỏng được kích hoạt để đảm bảo hầu hết các trang web được tối ưu hoá không cho thao tác chạm vẫn hoạt động. Ví dụ: đối với một lần nhấn vào màn hình, các sự kiện này có thể được kích hoạt theo trình tự nhanh và theo thứ tự sau:

  1. khởi động bằng thao tác chạm
  2. di chuyển cảm ứng
  3. điểm cuối
  4. di chuột qua
  5. mousemove
  6. di chuột xuống
  7. chuột lên
  8. click

Nếu bạn có các tương tác phức tạp hơn một chút, những sự kiện chuột này có thể gây ra một số hành vi ngoài dự kiến và gây xáo trộn quá trình triển khai của bạn. Thông thường, tốt nhất là bạn nên sử dụng event.preventDefault() trong trình xử lý sự kiện chạm và quản lý hoạt động đầu vào bằng chuột trong các trình xử lý sự kiện riêng biệt. Bạn cần lưu ý rằng việc sử dụng event.preventDefault() trong trình xử lý sự kiện chạm cũng sẽ ngăn chặn một số hành vi mặc định, chẳng hạn như cuộn và sự kiện nhấp chuột.

"Trong ứng dụng Xây dựng với Chrome, chúng tôi không muốn thu phóng xảy ra khi ai đó nhấn đúp vào trang web, mặc dù đây là chức năng tiêu chuẩn trong hầu hết các trình duyệt. Vì vậy, chúng tôi sử dụng thẻ meta chế độ xem để yêu cầu trình duyệt không thu phóng khi người dùng nhấn đúp. Thao tác này cũng loại bỏ độ trễ nhấp chuột 300 mili giây, giúp cải thiện khả năng phản hồi của trang web. (Độ trễ nhấp chuột được dùng để phân biệt giữa một lần nhấn và một lần nhấn đúp khi thu phóng bằng cách nhấn đúp được bật).

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

Hãy nhớ rằng khi sử dụng tính năng này, bạn có quyền quyết định làm cho trang web có thể đọc được trên tất cả các kích thước màn hình vì người dùng sẽ không thể thu phóng gần hơn.

Nhập bằng chuột, thao tác chạm và bàn phím

Trong chế độ Khám phá 3D, chúng tôi muốn có ba cách để điều hướng bản đồ: chuột (kéo), chạm (kéo, chụm để thu phóng và xoay) và bàn phím (điều hướng bằng các phím mũi tên). Tất cả các phương thức điều hướng này hoạt động hơi khác nhau, nhưng chúng tôi đã sử dụng cùng một phương pháp trên tất cả các phương thức đó; đặt biến trong trình xử lý sự kiện và hành động theo điều đó trong vòng lặp requestAnimationFrame. Vòng lặp requestAnimationFrame không nhất thiết phải biết phương thức nào được dùng để điều hướng.

Ví dụ: chúng ta có thể thiết lập chuyển động của bản đồ (kéoDX và kéo dài) bằng cả ba phương thức nhập. Dưới đây là cách triển khai bàn phím:

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

Ví dụ được nhúng: Sử dụng chuột, thao tác chạm và bàn phím để di chuyển: http://cdpn.io/catlf

Tóm tắt

Điều chỉnh ứng dụng Xây dựng với Chrome để hỗ trợ các thiết bị cảm ứng có nhiều kích thước màn hình khác nhau quả là một trải nghiệm học hỏi. Nhóm này không có nhiều kinh nghiệm khi thực hiện mức độ tương tác này trên thiết bị cảm ứng và chúng tôi đã học được rất nhiều kiến thức trong quá trình này.

Thử thách lớn nhất hoá ra lại là làm sao giải quyết được trải nghiệm người dùng và thiết kế. Những thách thức về kỹ thuật là quản lý nhiều kích thước màn hình, sự kiện chạm và vấn đề về hiệu suất.

Mặc dù gặp một số khó khăn với trình đổ bóng WebGL trên thiết bị cảm ứng, nhưng đây là tính năng hoạt động gần như tốt hơn mong đợi. Các thiết bị ngày càng mạnh mẽ hơn và việc triển khai WebGL cũng được cải thiện nhanh chóng. Chúng tôi cảm thấy rằng chúng tôi sẽ sử dụng WebGL trên các thiết bị nhiều hơn trong tương lai gần.

Bây giờ, hãy xây dựng một ứng dụng tuyệt vời nếu bạn chưa làm vậy!