멀티스크린 웹에 LEGO® 블록 가져오기
원래 오스트레일리아에서 출시된 데스크톱 Chrome 사용자를 위한 재미있는 실험인 Build with Chrome은 2014년에 전 세계에서 사용할 수 있게 되었으며, THE LEGO® MOVIE™와의 제휴, 모바일 기기 지원을 새로 추가했습니다. 이 도움말에서는 특히 데스크톱 전용 환경에서 마우스와 터치 입력을 모두 지원하는 멀티스크린 솔루션으로 전환하는 것과 관련하여 프로젝트에서 얻은 몇 가지 사항을 공유합니다.
Chrome을 통한 빌드의 역사
Build with Chrome의 첫 번째 버전은 2012년 오스트레일리아에서 출시되었습니다. Google은 웹의 위력을 완전히 새로운 방식으로 보여주고 완전히 새로운 사용자층에게 Chrome을 알리고자 했습니다.
이 사이트는 두 가지 주요 부분으로 구성되어 있습니다. 사용자가 레고 블록을 사용하여 작품을 만들 수 있는 '빌드' 모드와 레고 버전의 Google 지도에서 작품을 둘러볼 수 있는 '탐색' 모드입니다.
사용자에게 최고의 레고 빌딩 환경을 제공하려면 양방향 3D가 필요했습니다. 2012년에는 WebGL이 데스크톱 브라우저에서만 공개적으로 제공되었으므로 Build는 데스크톱 전용 환경으로 타겟팅되었습니다. 탐색에서는 Google 지도를 사용하여 창작물을 표시했지만 충분히 확대하면 Google 지도를 기반판 텍스처로 계속 사용하면서 창작물을 3D로 보여주는 지도의 WebGL 구현으로 전환되었습니다. 모든 연령대의 레고 애호가가 자신의 창의성을 쉽고 직관적으로 표현하고 서로의 창작물을 탐색할 수 있는 환경을 만들고자 했습니다.
2013년 Google은 Build with Chrome을 새로운 웹 기술로 확장하기로 결정했습니다. 이러한 기술 중에는 Android용 Chrome의 WebGL이 있었는데, 이로 인해 Build with Chrome이 자연스럽게 모바일 환경으로 발전할 수 있었습니다. 먼저 터치 프로토타입을 개발한 후 '빌더 도구'의 하드웨어를 조사하여 모바일 앱과 비교하여 브라우저를 통해 발생할 수 있는 동작 동작과 촉각 응답성을 파악했습니다.
반응형 프런트엔드
터치와 마우스 입력이 모두 있는 기기를 지원해야 했습니다. 하지만 작은 터치 스크린에서 동일한 UI를 사용하면 공간 제약으로 인해 최적의 솔루션이 되지 않았습니다.
Build에는 확대/축소, 벽돌 색상 변경, 벽돌 선택, 회전, 배치 등 다양한 상호작용이 있습니다. 사용자가 많은 시간을 보내는 도구이므로 자주 사용하는 모든 항목에 빠르게 액세스할 수 있어야 하며 편안하게 상호작용할 수 있어야 합니다.
상호작용이 많은 터치 애플리케이션을 디자인할 때는 화면이 금방 작아 보이고 사용자가 상호작용하는 동안 손가락이 화면의 상당 부분을 가리는 경향이 있습니다. 이는 빌더를 사용할 때 분명해졌습니다. 디자인할 때는 그래픽의 픽셀이 아닌 실제 화면 크기를 고려해야 합니다. 실제 콘텐츠에 최대한 많은 화면 공간을 할당하려면 버튼과 컨트롤 수를 최소화하는 것이 중요합니다.
Google의 목표는 원래 데스크톱 구현에 터치 입력을 추가하는 것이 아니라 터치 기기에서 Build가 자연스럽게 느껴지도록 하는 것이었습니다. 결국 대형 화면이 있는 데스크톱 및 태블릿용 UI와 소형 화면이 있는 휴대기기용 UI의 두 가지 변형이 만들어졌습니다. 가능하면 단일 구현을 사용하고 모드 간에 원활하게 전환하는 것이 가장 좋습니다. Google에서는 두 모드 간에 경험의 차이가 너무 커서 특정 중단점을 사용하기로 결정했습니다. 두 버전에는 많은 공통 기능이 있으며 하나의 코드 구현으로 대부분의 작업을 수행하려고 했지만 UI의 일부 측면은 두 버전 간에 다르게 작동합니다.
YouTube는 사용자 에이전트 데이터를 사용하여 휴대기기를 감지한 다음 표시 영역 크기를 확인하여 소형 화면 모바일 UI를 사용해야 하는지 결정합니다. 실제 화면 크기의 신뢰할 수 있는 값을 가져오기가 어렵기 때문에 '대형 화면'의 중단점을 선택하기는 쉽지 않습니다. 다행히 이 경우 대형 화면의 터치 기기에 소형 화면 UI를 표시해도 상관없습니다. 도구는 계속 잘 작동하지만 일부 버튼이 약간 너무 커 보일 수 있습니다. 마지막으로 중단점을 1, 000픽셀로 설정합니다. 1,000픽셀보다 넓은 창 (가로 모드)에서 사이트를 로드하면 대형 화면 버전이 표시됩니다.
두 가지 화면 크기와 환경에 대해 간단히 알아보겠습니다.
마우스 및 터치 지원이 있는 대형 화면
대형 화면 버전은 마우스를 지원하는 모든 데스크톱 컴퓨터와 대형 화면이 있는 터치 기기 (예: Google Nexus 10)에 제공됩니다. 이 버전은 사용 가능한 탐색 컨트롤의 종류가 원래 데스크톱 솔루션과 비슷하지만 터치 지원과 일부 동작이 추가되었습니다. 창 크기에 따라 UI가 조정되므로 사용자가 창 크기를 조절하면 일부 UI가 삭제되거나 크기가 조절될 수 있습니다. CSS 미디어 쿼리를 사용하여 이 작업을 수행합니다.
예: 사용 가능한 높이가 730픽셀 미만이면 살펴보기 모드의 확대/축소 슬라이더 컨트롤이 숨겨집니다.
@media only screen and (max-height: 730px) {
.zoom-slider {
display: none;
}
}
작은 화면, 터치 지원만 해당
이 버전은 휴대기기 및 소형 태블릿 (타겟 기기 Nexus 4 및 Nexus 7)에 제공됩니다. 이 버전에는 멀티 터치 지원이 필요합니다.
소형 화면 기기에서는 콘텐츠에 최대한 많은 화면 공간을 제공해야 하므로 주로 자주 사용하지 않는 요소를 보이지 않게 하여 공간을 최대화하는 몇 가지 조정을 했습니다.
- 빌드 중에는 빌드 브릭 선택기가 색상 선택기로 최소화됩니다.
- 확대/축소 및 방향 컨트롤을 멀티 터치 제스처로 대체했습니다.
- Chrome 전체 화면 기능은 추가 화면 공간을 확보하는 데도 유용합니다.
WebGL 성능 및 지원
최신 터치 기기에는 매우 강력한 GPU가 있지만 데스크톱 GPU에 비하면 아직 멀기 때문에 성능에 문제가 있을 수 있다는 것을 알고 있었습니다. 특히 여러 창작물을 동시에 렌더링해야 하는 3D 탐색 모드에서 성능 문제가 발생할 수 있습니다.
창의적인 측면에서 복잡한 도형과 투명성까지 갖춘 새로운 유형의 브릭을 몇 가지 추가하고자 했습니다. 이러한 기능은 일반적으로 GPU에 매우 큰 부하를 줍니다. 하지만 하위 호환성을 유지하고 첫 번째 버전의 작품을 계속 지원해야 했기 때문에 작품의 총 브릭 수를 크게 줄이는 등의 새로운 제한사항을 설정할 수 없었습니다.
Build의 첫 번째 버전에서는 한 번의 제작에 사용할 수 있는 최대 브릭 수가 제한되었습니다. 남은 벽돌 수를 나타내는 '벽돌 미터'가 있었습니다. 새 구현에서는 표준 브릭보다 브릭 미터에 더 많은 영향을 미치는 일부 새 브릭이 있었기 때문에 총 최대 브릭 수가 약간 줄었습니다. 이는 적절한 성능을 유지하면서 새 브릭을 포함하는 한 가지 방법이었습니다.
3D 탐색 모드에서는 동시에 여러 작업이 진행됩니다. 기본판 텍스처 로드, 제작물 로드, 제작물 애니메이션 및 렌더링 등 이렇게 하려면 GPU와 CPU 모두에 많은 작업이 필요하므로 Chrome DevTools에서 이러한 부분을 최대한 최적화하기 위해 많은 프레임 프로파일링을 수행했습니다. 휴대기기에서는 한 번에 많은 수의 작품을 렌더링하지 않아도 되도록 작품을 좀 더 확대하기로 결정했습니다.
일부 기기에서는 일부 WebGL 셰이더를 다시 살펴보고 단순화해야 했지만 항상 문제를 해결하고 계속 진행할 방법을 찾았습니다.
WebGL 이외의 기기 지원
방문자의 기기에서 WebGL을 지원하지 않더라도 사이트를 어느 정도 사용할 수 있도록 했습니다. 캔버스 솔루션이나 CSS3D 기능을 사용하여 3D를 간소화된 방식으로 표현하는 방법이 있는 경우도 있습니다. 안타깝게도 WebGL을 사용하지 않고 3D 빌드 및 탐색 기능을 복제할 수 있는 적절한 솔루션을 찾지 못했습니다.
일관성을 위해 모든 플랫폼에서 콘텐츠의 시각적 스타일이 동일해야 합니다. 2.5D 솔루션을 시도할 수도 있었지만, 이 경우 어떤 면에서는 창작물이 다르게 보일 수 있었습니다. 또한 Build with Chrome의 첫 번째 버전으로 빌드된 창작물이 새 버전의 사이트에서 첫 번째 버전과 동일하게 보이고 원활하게 실행되도록 하는 방법도 고려해야 했습니다.
새 창작물을 빌드하거나 3D로 탐색할 수는 없지만 WebGL이 아닌 기기에서도 탐색 2D 모드를 계속 사용할 수 있습니다. 따라서 사용자는 WebGL 지원 기기를 사용하는 경우에도 프로젝트의 심도와 이 도구를 사용하여 만들 수 있는 항목을 파악할 수 있습니다. WebGL을 지원하지 않는 사용자에게는 사이트의 가치가 떨어질 수 있지만, 적어도 티저 역할을 하여 사용자의 참여를 유도해야 합니다.
WebGL 솔루션의 대체 버전을 유지하는 것이 불가능한 경우도 있습니다. 성능, 시각적 스타일, 개발 및 유지보수 비용 등 다양한 이유가 있을 수 있습니다. 하지만 대체 옵션을 구현하지 않기로 결정한 경우에도 최소한 WebGL을 지원하지 않는 방문자를 고려해야 합니다. 이러한 방문자가 사이트에 완전히 액세스할 수 없는 이유를 설명하고 WebGL을 지원하는 브라우저를 사용하여 문제를 해결하는 방법을 안내해야 합니다.
저작물 관리
2013년 Google은 출시 이후 가장 중요한 UI 변경사항이 포함된 새 버전의 Google 지도를 도입했습니다. 이에 따라 새로운 Google 지도 UI에 맞게 Build with Chrome을 다시 디자인하기로 결정했으며, 이를 위해 다른 요소도 디자인에 반영했습니다. 새로운 디자인은 깔끔한 단색과 단순한 도형을 사용하여 비교적 평면적입니다. 이를 통해 많은 UI 요소에 순수 CSS를 사용하여 이미지 사용을 최소화할 수 있었습니다.
탐색에서는 많은 이미지를 로드해야 합니다. 작품의 썸네일 이미지, 베이스플레이트의 텍스처 맵, 마지막으로 실제 3D 작품이 여기에 해당합니다. Google은 새 이미지를 지속적으로 로드할 때 메모리 누출이 발생하지 않도록 각별히 주의하고 있습니다.
3D 제작물은 PNG 이미지로 패키징된 맞춤 파일 형식으로 저장됩니다. 3D 제작물 데이터를 이미지로 저장하면 기본적으로 제작물을 렌더링하는 셰이더에 데이터를 직접 전달할 수 있었습니다.
모든 사용자 제작 이미지의 경우 이 디자인을 통해 모든 플랫폼에 동일한 이미지 크기를 사용할 수 있으므로 스토리지와 대역폭 사용량을 최소화할 수 있었습니다.
화면 방향 관리
세로 모드에서 가로 모드로 또는 그 반대로 전환할 때 화면 가로세로 비율이 얼마나 달라지는지 잊어버리기 쉽습니다. 모바일 기기에 맞게 조정할 때는 처음부터 이 점을 고려해야 합니다.
스크롤이 사용 설정된 기존 웹사이트에서 CSS 규칙을 적용하여 콘텐츠와 메뉴를 재정렬하는 반응형 사이트를 만들 수 있습니다. 스크롤 기능을 사용할 수 있다면 비교적 쉽게 관리할 수 있습니다.
Build에서도 이 메서드를 사용했지만 콘텐츠를 항상 표시하고 여러 컨트롤과 버튼에 빠르게 액세스해야 하므로 레이아웃을 해결하는 방법이 다소 제한적이었습니다. 뉴스 사이트와 같은 순수 콘텐츠 사이트의 경우 유연한 레이아웃이 매우 적합하지만 저희와 같은 게임 앱의 경우 어려움이 있었습니다. 콘텐츠의 개요를 잘 살리면서도 편안한 상호작용 방식을 유지하면서 가로 모드와 세로 모드 방향에서 모두 작동하는 레이아웃을 찾는 것이 과제였습니다. 결국 Build를 가로 모드로만 유지하고 사용자에게 기기를 회전하도록 안내하기로 결정했습니다.
탐색은 두 방향 모두에서 훨씬 더 쉽게 해결할 수 있었습니다. 일관된 환경을 제공하기 위해 방향에 따라 3D의 확대/축소 수준을 조정하기만 하면 됩니다.
대부분의 콘텐츠 레이아웃은 CSS로 제어되지만 일부 방향 관련 항목은 JavaScript로 구현해야 했습니다. window.orientation을 사용하여 방향을 식별하는 적절한 교차 기기 솔루션이 없으므로 결국 window.innerWidth와 window.innerHeight를 비교하여 기기의 방향을 식별했습니다.
if( window.innerWidth > window.innerHeight ){
//landscape
} else {
//portrait
}
터치 지원 추가
웹 콘텐츠에 터치 지원을 추가하는 것은 비교적 간단합니다. 클릭 이벤트와 같은 기본 상호작용은 데스크톱과 터치 지원 기기에서 동일하게 작동하지만, 고급 상호작용의 경우 터치 이벤트(touchstart, touchmove, touchend)도 처리해야 합니다. 이 도움말에서는 이러한 이벤트를 사용하는 방법을 기본적으로 설명합니다. Internet Explorer는 터치 이벤트를 지원하지 않고 대신 포인터 이벤트 (pointerdown, pointermove, pointerup)를 사용합니다. 포인터 이벤트는 표준화를 위해 W3C에 제출되었지만 현재는 Internet Explorer에서만 구현됩니다.
Explore 3D 모드에서는 표준 Google 지도 구현과 동일한 탐색을 사용하고자 했습니다. 한 손가락을 사용해 지도를 화면 안에서 이동하고 두 손가락을 모아 확대/축소합니다. 제작물이 3D이므로 두 손가락 회전 동작도 추가했습니다. 일반적으로 터치 이벤트를 사용해야 합니다.
이벤트 핸들러에서 3D를 업데이트하거나 렌더링하는 등 컴퓨팅이 많이 소요되는 작업은 피하는 것이 좋습니다. 대신 터치 입력을 변수에 저장하고 requestAnimationFrame 렌더링 루프에서 입력에 반응합니다. 이렇게 하면 마우스 구현도 동시에 더 쉽게 할 수 있습니다. 상응하는 마우스 값을 동일한 변수에 저장하기만 하면 됩니다.
먼저 입력을 저장할 객체를 초기화하고 touchstart 이벤트 리스너를 추가합니다. 각 이벤트 핸들러에서 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);
}
}
이벤트 핸들러에서 입력을 실제로 저장하지는 않고 별도의 핸들러인 handleDragStart, handleDragging, handleDragStop에서 저장합니다. 마우스 이벤트 핸들러에서도 이를 호출할 수 있기 때문입니다. 사용자가 터치와 마우스를 동시에 사용할 가능성은 낮지만 이를 고려해야 합니다. Google에서는 해당 케이스를 직접 처리하지 않고 문제가 발생하지 않도록 합니다.
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를 기반으로 애니메이션을 실행할 때는 마지막 이벤트 이후의 이동 델타도 저장하는 것이 유용합니다. 예를 들어 탐색에서 모든 베이스 플레이트를 이동할 때 카메라의 속도 매개변수로 사용했습니다. 베이스 플레이트를 드래그하는 것이 아니라 실제로 카메라를 움직이기 때문입니다.
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;
}
삽입된 예시: 터치 이벤트를 사용하여 객체를 드래그합니다. Build 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;
}
그런 다음 touchmove 이벤트에서 두 손가락 사이의 거리와 각도를 연속적으로 측정합니다. 그런 다음 시작 거리와 현재 거리의 차이를 사용하여 크기를 설정하고 시작 각도와 현재 각도의 차이를 사용하여 각도를 설정합니다.
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;
}
}
드래그와 관련된 예와 비슷한 방식으로 각 touchmove 이벤트 간의 거리 변화를 사용할 수도 있지만, 이 접근 방식은 연속적인 움직임을 원할 때 더 유용합니다.
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에서 객체를 회전하고 크기 조정합니다. 탐색의 지도 구현 방식과 유사합니다. http://cdpn.io/izloq
동일한 하드웨어에서 마우스 및 터치 지원
현재 마우스와 터치 입력을 모두 지원하는 Chromebook Pixel과 같은 노트북 컴퓨터가 여러 대 있습니다. 주의하지 않으면 예기치 않은 동작이 발생할 수 있습니다.
중요한 점은 터치 지원을 감지한 다음 마우스 입력을 무시하는 것이 아니라 둘 다 동시에 지원해야 한다는 것입니다.
터치 이벤트 핸들러에서 event.preventDefault()
를 사용하지 않는 경우 대부분의 터치가 아닌 최적화된 사이트가 계속 작동하도록 하기 위해 에뮬레이션된 마우스 이벤트도 실행됩니다. 예를 들어 화면을 한 번 탭하면 다음 이벤트가 빠른 순서대로 다음과 같은 순서로 실행될 수 있습니다.
- touchstart
- touchmove
- touchend
- 마우스 오버
- mousemove
- mousedown
- mouseup
- 클릭
상호작용이 조금 더 복잡한 경우 이러한 마우스 이벤트로 인해 예기치 않은 동작이 발생하고 구현이 손상될 수 있습니다. 터치 이벤트 핸들러에서 event.preventDefault()
를 사용하고 별도의 이벤트 핸들러에서 마우스 입력을 관리하는 것이 가장 좋습니다. 터치 이벤트 핸들러에서 event.preventDefault()
를 사용하면 스크롤 및 클릭 이벤트와 같은 일부 기본 동작도 방지된다는 점에 유의해야 합니다.
"Build with Chrome에서는 사용자가 사이트를 더블탭할 때 확대/축소가 발생하지 않도록 했습니다. 이는 대부분의 브라우저에서는 표준이지만 따라서 뷰포트 메타 태그를 사용하여 사용자가 더블탭할 때 브라우저가 확대/축소하지 않도록 지시합니다. 또한 클릭 지연 시간 300ms가 사라져 사이트의 응답성이 개선됩니다. 클릭 지연은 더블탭 확대/축소가 사용 설정된 경우 한 번 탭과 두 번 탭을 구분하기 위한 것입니다.
<meta name="viewport" content="width=device-width,user-scalable=no">
이 기능을 사용할 때는 사용자가 더 확대할 수 없으므로 모든 화면 크기에서 사이트를 읽을 수 있도록 해야 합니다.
마우스, 터치, 키보드 입력
탐색 3D 모드에서는 마우스 (드래그), 터치 (드래그, 손가락 모으기 확대/축소 및 회전), 키보드 (화살표 키로 탐색)의 세 가지 방법으로 지도를 탐색할 수 있도록 했습니다. 이러한 모든 탐색 메서드는 약간 다르게 작동하지만 모두 동일한 접근 방식을 사용했습니다. 이벤트 핸들러에서 변수를 설정하고 requestAnimationFrame 루프에서 이에 따라 작업합니다. requestAnimationFrame 루프는 탐색하는 데 사용되는 메서드를 알 필요가 없습니다.
예를 들어 세 가지 입력 메서드를 모두 사용하여 지도의 움직임 (dragDX 및 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을 훨씬 더 많이 사용하게 될 것으로 예상됩니다.
아직 시작하지 않았다면 멋진 앱을 만들어 보세요.