# 픽셀 단위 스크롤 

## Content

SpreadJS는 Excel과 유사한 **정밀 스크롤** 기능을 폭넓게 지원하여, 부드럽고 매끄러운 스크롤 경험을 제공하며 워크시트를 더욱 세밀하게 제어할 수 있도록 합니다.
사용자는 스프레드시트를 수동 또는 자동으로 픽셀 단위로 스크롤할 수 있습니다. 수동 스크롤링에서는 픽셀을 설정하고 스크롤바 끝에 있는 화살표를 사용하여 가로 또는 세로 방향으로 지정된 픽셀만큼 스프레드시트를 스크롤할 수 있습니다. 반면에 자동 스크롤링에서는 가로 및 세로 픽셀을 설정하여 스프레드시트를 지정된 픽셀만큼 자동으로 스크롤할 수 있습니다.

## 픽셀 스크롤의 장점

픽셀 단위로 스크롤하면 워크시트의 셀을 더욱 정밀하게 탐색할 수 있어 사용자 경험이 크게 향상됩니다.
픽셀 스크롤은 다음과 같은 상황에서 유용하게 활용됩니다:

* 셀 높이가 매우 크거나(여러 줄의 텍스트 포함), 열 너비가 넓은 경우
* 사용자가 행 또는 열의 가장자리를 드래그하여 크기를 조정하려는 경우
* 사용자가 셀 내부에 도형이나 이미지를 배치하려는 경우
* 한 셀에 많은 데이터를 입력해야 하는 경우 (예: 입력 폼, 설문 폼, 기록 등)
* 태블릿이나 모바일처럼 화면이 작은 기기에서 워크시트를 스크롤할 때
* 특정 뷰포트 또는 원하는 데이터가 있는 셀로 정확하게 이동하고 싶을 때

## 지원되는 사용자 인터랙션

가로 및 세로 방향 모두에서 **픽셀 단위 스크롤**이 가능합니다.
SpreadJS는 다음과 같은 마우스휠 및 키보드/터치 동작을 지원합니다:

* 행 뷰포트 인덱스 1 또는 열 뷰포트 인덱스 1의 뷰포트 영역에서 마우스휠 또는 트랙패드 사용
* 스크롤바의 상/하/좌/우 버튼 클릭 시 마우스휠 또는 트랙패드 사용
* 스크롤바의 화살표 버튼, 마우스휠, 트랙패드를 이용한 스크롤
* 뷰포트 영역에서의 터치 스크롤
* 스크롤바의 좌/우/상/하 버튼 또는 트랙 버튼을 터치하거나 탭

## 픽셀 스크롤 활성화 (수동)

기본적으로 Excel과 SpreadJS는 **행 또는 열 단위로만 스크롤**됩니다.
픽셀 단위 스크롤을 활성화하려면 **scrollByPixel** 속성을 "true"로 설정하면 됩니다.
설정 후에는 스크롤바 끝의 화살표를 사용하여 지정된 픽셀만큼 수동으로 스크롤할 수 있습니다.

## 사용 예시

예를 들어, 여러 나라 및 해당 국가의 주별 제품 분석 데이터를 포함하는 워크시트를 작업 중이라고 가정해 봅시다. 행과 열을 스크롤하면서 특정 국가의 마지막 주나 마지막 제품 정보를 보고 싶을 때, 기본 스크롤은 전체 행 또는 열 단위로 이동하므로 세부 항목을 놓치기 쉽습니다. 이 경우 **픽셀 스크롤링**을 사용하면 보다 정밀하게 원하는 위치를 탐색할 수 있어 편리합니다.
아래 이미지는 워크시트에서 **픽셀 단위 스크롤**이 작동하는 모습을 보여줍니다.
![](https://gcdocumentsitekrblob.blob.core.windows.net/document-site-files/images/8d606653-16a0-474d-b9dc-e2b4d01c2446/images/pixelaccurate-scrolling.gif)

```auto
// 픽셀 단위의 정밀 스크롤 활성화
spread.options.scrollByPixel = true;
spread.options.scrollPixel = 5;
```

**참고:** 스프레드시트에서 픽셀 스크롤 기능을 사용할 때는 다음과 같은 제한 사항을 염두에 두어야 합니다:

* 터치 기반 장치에서 픽셀 단위로 스크롤할 경우, **터치 제스처는 경계 피드백 효과나 전체 행/열 단위 스크롤을 지원하지 않습니다**.
* **스프레드시트를 PDF로 내보내거나 인쇄할 때는 픽셀 스크롤 기능을 사용할 수 없습니다.** 하지만 픽셀 스크롤은 그 외의 모든 기능과는 문제 없이 함께 사용할 수 있습니다.

## 코드 사용 예

다음 예제 코드는 사용자가 원하는 대로 **픽셀 크기를 설정**하고, 워크시트에서 **행과 열을 픽셀 단위로 스크롤**할 수 있도록 합니다.

```js
    var data = [
   {
       Country: "Canada",
       State: "Ontario",
       City: "Ottawa",
       Product: "Kraft Grated Parmesan Cheese",
   },
   {
       Country: "Canada",
       State: "Ontario",
       City: "Belleville",
       Product: "KIND Bars Almond & Coconut Gluten Free",
   },
   {
       Country: "Canada",
       State: "Ontario",
       City: "Alliston",
       Product: "Kraft Grated Parmesan Cheese",
   },
   {
       Country: "Canada",
       State: "Saskatchewan",
       City: "Prince Albert",
       Product: "Smartfood Popcorn",
   },
   {
       Country: "Canada",
       State: "Alberta",
       City: "Red Deer",
       Product: "Smartfood Popcorn",
   },
   {
       Country: "Canada",
       State: "Alberta",
       City: "Calgary",
       Product: "Planters Deluxe Whole Cashew",
   },
   {
       Country: "Canada",
       State: "Alberta",
       City: "Calgary",
       Product: "Kraft Grated Parmesan Cheese",
   },
   {
       Country: "Canada",
       State: "Alberta",
       City: "Okotoks",
       Product: "Smartfood Popcorn",
   },
   {
       Country: "India",
       State: "Andhra Pradesh",
       City: "Hyderabad",
       Product: "Teddy Grahams Crackers",
   },
   {
       Country: "South Africa",
       State: "Gauteng",
       City: "Roodepoort",
       Product: "Jaybee's Gourmet Nuts Gift Pack (3 Lb)",
   },
   {
       Country: "Finland",
       State: "Ita-Suomen Laani",
       City: "Kuopio",
       Product: "Planters Deluxe Whole Cashew",
   },
   {
       Country: "Switzerland",
       State: "Geneve",
       City: "Vesenaz",
       Product: "KIND Bars Almond & Coconut Gluten Free",
   },
   {
       Country: "Switzerland",
       State: "Vaud",
       City: "Lausanne",
       Product: "Smartfood Popcorn",
   },
   {
       Country: "Switzerland",
       State: "Vaud",
       City: "Morges",
       Product: "Kraft Real Mayo",
   },
   {
       Country: "Denmark",
       State: "Frederiksborg",
       City: "Helsingor",
       Product: "Planters Deluxe Whole Cashew",
   },
   {
       Country: "Denmark",
       State: "Kobenhavn",
       City: "Kobenhavn",
       Product: "Kraft Grated Parmesan Cheese",
   },
   {
       Country: "Denmark",
       State: "Storstrom",
       City: "Nakskov",
       Product: "Kraft Grated Parmesan Cheese",
   },
   ];

   $(document).ready(function () {
   // 스프레드 초기화
   var spread = new GC.Spread.Sheets.Workbook(document.getElementById("ss"), {
       sheetCount: 1,
   });

   // 활성 시트 가져오기
   var sheet = spread.getSheet(0);
   spread.suspendPaint();

   // 픽셀 단위의 정밀 스크롤 활성화
   spread.options.scrollByPixel = true;

   // 데이터 소스 바인딩
   sheet.setRowHeight(0, 30, 1);
   sheet.autoGenerateColumns = false;
   sheet.setDataSource(data);
   var colInfos = [
       { name: "Country", size: 180 },
       { name: "State", size: 120 },
       { name: "City", size: 120 },
       { name: "Product", size: 280 },
   ];
   sheet.bindColumns(colInfos);

   // 셀 병합 추가
   var defaultStyle = sheet.getDefaultStyle();
   defaultStyle.vAlign = GC.Spread.Sheets.VerticalAlign.center;
   defaultStyle.hAlign = GC.Spread.Sheets.HorizontalAlign.center;
   sheet.setDefaultStyle(defaultStyle);
   var cc = sheet.getColumnCount(),
       rc = sheet.getRowCount();
   for (var c = 0; c < cc; c++) {
       var tempValue = null,
       tempRow = -1,
       tempRowCount = -1;
       for (var r = 0; r < rc; r++) {
       var cellValue = sheet.getValue(r, c);
       if (tempValue == null) {
           tempValue = cellValue;
           tempRow = r;
           tempRowCount = 1;
       } else if (tempValue === cellValue) {
           tempRowCount++;
       } else {
           if (tempRowCount > 1) {
           sheet.addSpan(tempRow, c, tempRowCount, 1);
           }
           tempValue = cellValue;
           tempRow = r;
           tempRowCount = 1;
       }
       }
       if (tempRowCount > 1) {
       sheet.addSpan(tempRow, c, tempRowCount, 1);
       }
   }
   spread.resumePaint();
   // scrollByPixel 설정을 위한 이벤트 바인딩
   var scrollByPixel = document.getElementById("scrollByPixel");
   scrollByPixel.addEventListener("change", function () {
       spread.options.scrollByPixel = scrollByPixel.checked;
   });
   var scrollPixel = document.getElementById("scrollPixel");
   document
       .getElementById("setScrollPixel")
       .addEventListener("click", function () {
       spread.options.scrollPixel = parseInt(scrollPixel.value);
       });
   });
```

## 픽셀 스크롤 활성화 (자동)

**scroll** 메서드와 함께, **scrollByPixel** 속성도 사용할 수 있으며, 이는 스크롤 동작에 다음과 같은 방식으로 영향을 줍니다:

* **scrollByPixel**이 true인 경우, 워크시트는 새 맨 위 행 또는 왼쪽 열 인덱스와 새 맨 위 행 또는 왼쪽 열 오프셋으로 스크롤됩니다 (scroll 메서드에서 정의된 대로)
* **scrollByPixel**이 false인 경우, 워크시트는 새 맨 위 행 또는 왼쪽 열 인덱스로만 스크롤되며 (scroll 메서드에서 정의된 대로), 새 맨 위 행 또는 왼쪽 열 오프셋은 항상 0이 됩니다

워크시트에서 **픽셀 단위의 자동 스크롤**을 활성화하려면 [scroll](/spreadjs/api/v18/classes/GC.Spread.Sheets.Worksheet#scroll) 메서드를 사용하면 됩니다. 이 메서드는 **세로 방향(vpixels)** 및 **가로 방향(hpixels)** 픽셀 수치를 설정하여 해당 방향으로 자동 스크롤을 수행할 수 있도록 합니다.

* 픽셀 값이 **양수**인 경우:
    * **vpixels**: 워크시트가 아래로 스크롤됩니다.
    * **hpixels**: 워크시트가 오른쪽으로 스크롤됩니다.
* 픽셀 값이 **음수**인 경우:
    * **vpixels**: 워크시트가 위로 스크롤됩니다.
    * **hpixels**: 워크시트가 왼쪽으로 스크롤됩니다.
* 픽셀 값이 **0**인 경우:
    * 워크시트는 어떤 방향으로도 스크롤되지 않습니다.

또한 **scroll** 메서드와 함께 **scrollByPixel** 속성을 설정하여 스크롤 동작을 다음과 같이 제어할 수 있습니다:

* **scrollByPixel** 이 **true**인 경우:
    워크시트는 scroll 메서드로 정의된 **새로운 상단 행/열 인덱스 및 오프셋 위치**로 스크롤됩니다.
* **scrollByPixel** 이 **false**인 경우:
    워크시트는 scroll 메서드로 정의된 **새로운 상단 행/열 인덱스**로만 스크롤되며, **오프셋은 항상 0**으로 고정됩니다.

## 사용 예시

예를 들어, 다양한 국가 및 각 국가의 주(state)별 제품 분석 데이터를 포함한 스프레드시트를 작업 중이라고 가정해봅시다. 행과 열을 스크롤하면서 **특정 국가에 대한 모든 데이터를 포함한 뷰포트**를 확인하고 싶을 경우, 자동 픽셀 스크롤 기능을 사용하면 원하는 데이터 영역으로 정확하게 이동하여 볼 수 있습니다.
아래 이미지는 워크시트에서 **자동 픽셀 스크롤**이 작동하는 모습을 보여줍니다.
![](https://gcdocumentsitekrblob.blob.core.windows.net/document-site-files/images/8d606653-16a0-474d-b9dc-e2b4d01c2446/images/automaticScroll.png)

## 코드 사용 예

다음 예제 코드는 사용자가 **가로 및 세로 방향에 대해 사용자 정의 픽셀 크기**를 설정하고, **워크시트에서 지정된 위치로 스크롤**할 수 있도록 합니다.

```js
// 활성화 시트 가져오기 
var activeSheet = spread.getActiveSheet();
spread.options.scrollByPixel = true;
// 이 예제는 시트를 아래 방향으로 30픽셀, 오른쪽으로 15픽셀 스크롤합니다.
activeSheet.scroll(30, 15);
```