# 스파크라인 규칙

## Content

스파크라인 규칙(Sparkline Rule)을 사용하면 조건부 서식을 통해 셀 값을 스파크라인으로 렌더링할 수 있습니다.
개별 셀에 스파크라인 수식을 삽입하는 대신 범위에 스파크라인 규칙을 적용할 수 있습니다. 이 규칙은 해당 범위의 각 셀에 대해 스파크라인을 자동으로 생성하고 렌더링합니다.
또한 규칙 범위와 현재 셀에 맞게 스파크라인 구성을 자동으로 조정하는 기본 제공 컨텍스트 식별자를 제공하여 하드 코딩된 참조를 제거합니다.
![image-20260325.27f2e0.png](https://gcdocumentsitekrblob.blob.core.windows.net/document-site-files/images/36b63360-fb01-457c-a448-c3ce32aaf454/image-20260325.27f2e0-20260529.3f2e6f.png?width=600)

## 스파크라인 규칙 사용 시점

다음과 같은 경우 스파크라인 규칙을 사용합니다.

* 전체 열, 행 또는 범위에 스파크라인 적용
* 워크시트 테이블, 테이블 시트 또는 데이터 매니저, 리포트 시트 템플릿과 같이 상관관계가 높은 데이터 영역에 스파크라인 추가
* 원본 셀 데이터를 변경하지 않기 위해 수식 기반 스파크라인 삽입 사용 방지
* 조건부 서식 우선순위를 통해 시각적 규칙 관리

## 스파크라인 규칙과 수식 기반 스파크라인의 차이점

기존 스파크라인은 각 셀에 스파크라인 함수를 작성하여 삽입합니다.
각 수식은 데이터 범위를 명시적으로 정의해야 하며, 필요한 경우 포인트 인덱스도 지정해야 합니다.
스파크라인 규칙은 다르게 동작합니다.

* 하나의 규칙을 범위에 적용
* 해당 범위의 각 셀이 스파크라인으로 렌더링됨
* 규칙이 자동으로 다음을 해석
    * 전체 규칙 범위
    * 현재 셀 값
    * 규칙 범위 내 현재 셀 위치

이 동작은 두 개의 기본 제공 컨텍스트 식별자를 통해 제공됩니다.

## 기본 제공 컨텍스트 식별자

스파크라인 조건부 서식 규칙은 두 가지 식별자를 지원합니다.

| 식별자 | 범위 | 용도 |
| --- | --- | --- |
| `$CF_RANGE$` | 규칙 수준 | 전체 조건부 서식 범위를 참조 |
| `@` | 셀 수준 | 현재 셀 값 또는 규칙 범위 내 인덱스를 참조 |

이 식별자는 다음과 같이 사용할 수 있습니다.

* 전체 매개변수 값으로 사용 (예: `value: '@'`, `points: '$CF_RANGE$'`)
* 식 내부에서 사용 (예: `IF(@>0,@,0)`, `SUM($CF_RANGE$)`)

`[@Sales]` 또는 `Table1[@[Column1]:[Column2]]`와 같은 구조화 참조는 원래 의미를 유지하며 플레이스홀더로 처리되지 않습니다.

### `$CF_RANGE$` — 규칙 수준 컨텍스트

`$CF_RANGE$`는 스파크라인 규칙이 적용된 **현재 범위**를 나타냅니다.
항상 규칙의 실제 조건부 서식 범위로 해석됩니다.

* 규칙이 `B1:B5`에 적용되면 `$CF_RANGE$`는 `B1:B5`로 해석됩니다.
* 규칙 범위가 `B1:B10`으로 변경되면 `$CF_RANGE$`도 자동으로 `B1:B10`으로 해석됩니다.

다음과 같이 데이터 범위를 하드 코딩하는 대신:

```javascript
dataRange: "A1:A5"
```

다음과 같이 작성할 수 있습니다.

```javascript
dataRange: "$CF_RANGE$"
```

예제:

```javascript
sheet.conditionalFormats.addSparklineRule(
    "HISTOGRAMSPARKLINE",
    {
        dataRange: "$CF_RANGE$"
    },
    [new GC.Spread.Sheets.Range(0, 0, 5, 1)]
);
```

**장점**

* 규칙 범위 변경 시 자동 반영
* 하드 코딩된 참조 제거
* `SUM($CF_RANGE$)`와 같은 식 지원
* 규칙 이식성 및 재사용성 향상

### `@` — 셀 수준 컨텍스트

`@`는 규칙 범위 내 **현재 셀**을 나타냅니다.
의미는 사용되는 매개변수에 따라 달라집니다.

* `index`에서 → `$CF_RANGE$` 내 현재 셀의 0 기반 인덱스
* `pointIndex`에서 → `$CF_RANGE$` 내 현재 셀의 1 기반 인덱스
* 기타 매개변수에서 → 현재 셀 값

`@`가 구조화 참조(예: `[@Sales]`) 안에 있으면 구조화 참조로서의 의미를 유지합니다.
`@`가 식 안에 포함되어 있고 현재 셀이 비어 있으면 식의 유효성을 유지하기 위해 빈 문자열 리터럴로 해석됩니다.
일부 스파크라인 유형은 `index`(0 기반)를 사용하고, 다른 유형은 `pointIndex`(1 기반)를 사용합니다. 유형별 매개변수 정의는 API 레퍼런스를 참조하세요.

## 예제 1: 값과 인덱스에 `@` 사용

다음 예제는 주문 처리 대시보드를 생성합니다.

* `On-Time KPI` 열에서 `@`는 현재 셀 값으로 해석됩니다.
* `Variance vs Target` 열에서 `@`는 규칙 범위 내 현재 행의 0 기반 인덱스로 해석됩니다.

```javascript
var sheet = spread.getActiveSheet();

// Title
sheet.addSpan(0, 0, 1, 6);
sheet.setValue(0, 0, "Weekly Fulfillment Dashboard");

// Header
sheet.setArray(1, 0, [[
    "Warehouse",
    "Target Units",
    "Shipped Units",
    "On-Time Rate",
    "On-Time KPI",
    "Variance vs Target"
]]);

// Data
var data = [
    ["North Hub",   1200, 1260, 1.05, 1.05],  // +5%
    ["East Hub",     950,  910, 0.96, 0.96],  // -4%
    ["South Hub",   1100, 1060, 0.96, 0.96],  // -3.6%
    ["West Hub",     780,  820, 1.05, 1.05],  // +5%
    ["Central Hub", 1350, 1290, 0.96, 0.96]   // -4.4%
];

sheet.setArray(2, 0, data);
sheet.getRange(2, 1, data.length, 2).formatter("#,##0");
sheet.getRange(2, 3, data.length, 2).formatter("0.0%");

// Optional column width for better visuals
sheet.getRange("A:D").width(120);
sheet.getRange("E:F").width(220);
sheet.getRange("3:7").height(42);

// Sparkline Rule
var cfs = sheet.conditionalFormats;

// @ = current cell value in E3:E7.
var gaugeRule = cfs.addSparklineRule(
    "GAUGEKPISPARKLINE",
    {
        targetValue: 1, // targetValue = 1 represents a 100% on-time fulfillment goal.
        currentValue: "@",
        minValue: 0,
        maxValue: 1.2,
        showLabel: false,
        gaugeType: 2,
        colorRange: [
            { start: 0, end: 0.9, color: "#D9534F" },
            { start: 0.9, end: 1, color: "#F0AD4E" },
            { start: 1, end: 1.2, color: "#5CB85C" }
        ]
    },
    [new GC.Spread.Sheets.Range(2, 4, data.length, 1)]
);

// @ = current row index inside F3:F7.
var varianceRule = cfs.addSparklineRule(
    "LOLLIPOPVARISPARKLINE",
    {
        plannedValue: "B3:B7",
        actualValue: "C3:C7",
        index: "@",
        reference: 0,
        mini: -0.15,
        maxi: 0.15,
        tickUnit: 0.05,
        legend: true,
        colorPositive: "#5CB85C",
        colorNegative: "#D9534F",
        lollipopHeaderColor: "#3F4E63"
    },
    [new GC.Spread.Sheets.Range(2, 5, data.length, 1)]
);
```

![image-20260414.bb79b2.png](https://gcdocumentsitekrblob.blob.core.windows.net/document-site-files/images/36b63360-fb01-457c-a448-c3ce32aaf454/image-20260414.bb79b2-20260529.c8c30b.png?width=600)
**동작 방식**

* `currentValue`에서 `@`는 `E3:E7` 범위의 각 셀 KPI 값으로 해석됩니다.
* `index`에서 `@`는 `F3:F7`에 대해 `0`, `1`, `2`, `3`, `4`로 해석됩니다.
* 게이지 규칙은 각 물류 센터가 100% 서비스 목표를 달성했는지 시각화합니다.
* 롤리팝 규칙은 하드 코딩된 행 인덱스 없이 각 행의 출하 수량과 목표 수량을 비교합니다.

>type=note
> **참고:**
> `plannedValue` 및 `actualValue` 범위는 이해를 돕기 위해 명시적으로(B3:B7 및 C3:C7) 작성되었습니다.
> 실제 환경에서는 하드 코딩된 주소를 피하기 위해 `$CF_RANGE$` 기반 식으로 대체할 수 있습니다.
> `$CF_RANGE$` 사용 방법은 예제 2를 참조하세요.

## 예제 2: `$CF_RANGE$`를 사용하여 하드 코딩된 데이터 범위 제거

다음 예제는 전체 규칙 범위를 컨텍스트로 사용하여 Variance 열의 각 셀에 롤리팝 분산 스파크라인을 렌더링합니다.

```javascript
var sheet = spread.getActiveSheet();

// Title
sheet.addSpan(0, 0, 1, 4);
sheet.setValue(0, 0, "Budget Variance Analysis");

// Headers
var headers = ["Department", "Planned ($K)", "Actual ($K)", "Variance"];
sheet.setArray(1, 0, [headers]);

// Data
var data = [
    ["R&D", 850, 760],
    ["Marketing", 420, 500],
    ["Sales", 380, 330],
    ["Support", 260, 305],
    ["Infrastructure", 520, 475]
];

sheet.setArray(2, 0, data);

// Optional column width for better visuals
sheet.getRange("A:D").width(150);

// Sparkline Rule (Advanced Usage)

sheet.conditionalFormats.addSparklineRule(
    "LOLLIPOPVARISPARKLINE",
    {
        // $CF_RANGE$  → D3:D7
        plannedValue: "OFFSET($CF_RANGE$,0,-2)",// Planned column → B
        actualValue: "OFFSET($CF_RANGE$,0,-1)",// Actual column → C
        index: "@",
        reference: 0,
        legend: true,
        colorPositive: "#4CAF50",
        colorNegative: "#E53935"
    },
    [new GC.Spread.Sheets.Range(2, 3, data.length, 1)]// Rule is applied to the Variance column (D3:D7)
);
```

![image-20260414.8d82f3.png](https://gcdocumentsitekrblob.blob.core.windows.net/document-site-files/images/36b63360-fb01-457c-a448-c3ce32aaf454/image-20260414.8d82f3-20260529.5cc7f2.png?width=600)
**유용한 이유**

* 규칙은 항상 현재 조건부 서식 범위를 기준으로 평가됩니다.
* 행을 추가하거나 삭제해도 계획 또는 실제 데이터 범위를 수정할 필요가 없습니다.
* 규칙은 이식 가능하며 자동으로 조정됩니다.

## 리포트 시트 템플릿 컨텍스트

<span style="color: #181818">리포트 시트 템플릿 </span>내에서 스파크라인 규칙을 사용하는 경우, 규칙은 런타임에 확장되는 템플릿 셀에 정의됩니다.
스파크라인 옵션이 템플릿 셀에서 생성된 확장 셀 범위를 참조해야 하는 경우 `R.V(...)` 수식을 사용합니다.
`R.V(reference)`는 지정한 템플릿 셀에 해당하는 런타임 확장 범위로 해석됩니다.
예제:
![image-20260420.da48ea.png](https://gcdocumentsitekrblob.blob.core.windows.net/document-site-files/images/36b63360-fb01-457c-a448-c3ce32aaf454/image-20260420.da48ea-20260529.5aa7cf.png?width=600)

```auto
const spread = new GC.Spread.Sheets.Workbook("ss");
const dataManager = spread.dataManager();

// 1. Data Source
const budgetData = [
    { department: "R&D", planned: 850, actual: 760 },
    { department: "Marketing", planned: 420, actual: 500 },
    { department: "Sales", planned: 380, actual: 330 },
    { department: "Support", planned: 260, actual: 305 },
    { department: "Infrastructure", planned: 520, actual: 475 }
];
dataManager.addTable("Budget", {
    data: budgetData
});

//2. Create ReportSheet
const reportSheet = spread.addSheetTab(
    0,
    "Budget Report",
    GC.Spread.Sheets.SheetType.reportSheet
);
const templateSheet = reportSheet.getTemplate();

const columns = ['department', 'planned', 'actual'];
columns.forEach((columnName, i) => {
    templateSheet.setValue(0, i, `${columnName}`);
    templateSheet.setTemplateCell(1, i, {
        type: 'List',
        binding: `Budget[${columnName}]`,
    });
    templateSheet.setColumnWidth(i, 80)
});
templateSheet.setValue(0, 3, "Variance");
templateSheet.setTemplateCell(1, 3, {
    type: "List"
});
templateSheet.setColumnWidth(3, 150);

//3. Sparkline Rule
templateSheet.conditionalFormats.addSparklineRule(
    "LOLLIPOPVARISPARKLINE",
    {
        plannedValue: "R.V(B2)",
        actualValue: "R.V(C2)",
        index: "@",
        reference: 0,
        legend: true,
        colorPositive: "#2E7D32",
        colorNegative: "#C62828"
    },
    [new GC.Spread.Sheets.Range(1, 3, 1, 1)]
);

// 4. Refresh
reportSheet.refresh();
```

**설명**

* 스파크라인 규칙은 템플릿 셀 D2에 정의됩니다.
* 보고서가 새로 고쳐지면 바인딩된 데이터를 기반으로 템플릿 행이 확장됩니다.
* `R.V(D2)`는 템플릿 셀 `D2`에 해당하는 확장된 런타임 범위로 해석됩니다.
* `index: '@'`는 규칙 범위 내 현재 셀의 0 기반 위치를 나타냅니다.

스파크라인 옵션이 템플릿 바인딩 셀에서 생성된 확장 범위를 참조해야 하는 경우 리포트 시트 템플릿에서 `R.V(...)`를 사용하세요.

## 동작 및 정책

* 지원되는 시트 유형: 워크시트, 테이블 시트, 리포트 시트
* `stopIfTrue`는 스파크라인 규칙에 대해 항상 `false`로 처리됩니다.
* 상대 참조는 조건부 서식 범위의 시작 위치를 기준으로 고정됩니다.
* 수식 형태의 옵션 값은 복사, 이동, 교체 및 시트 이름 변경 작업 중 참조 재기준 조정에 참여합니다.
* 스파크라인 규칙은 규칙 우선순위 순서에 참여합니다.

## Excel 내보내기

* **보기로 저장**이 활성화된 경우 → 이미지로 내보내기(권장)
* 그 외의 경우 → 일반 데이터 막대 규칙으로 다운그레이드
    * 스파크라인 전용 시각 효과는 유지되지 않습니다.
    * 규칙 우선순위만 유지됩니다.

## 디자이너 지원

디자이너에서 서식 스타일로 **스파크라인**을 선택하면:

* 속성 패널은 선택한 스파크라인 유형에 따라 동적으로 업데이트됩니다.
* 일부 속성은 기본적으로 **자동** 옵션을 표시합니다.
    * `ActualValue`의 기본값은 $CF\_RANGE$입니다.
    * `PointIndex`의 기본값은 @입니다.

![image-20260325.a7dff5.png](https://gcdocumentsitekrblob.blob.core.windows.net/document-site-files/images/36b63360-fb01-457c-a448-c3ce32aaf454/image-20260325.a7dff5-20260529.8c9408.png?width=400)
**자동**을 선택 해제하면 수동 구성이 가능합니다.

## 참고 항목

* [스파크라인](/spreadjs/docs/v19/features/sparkmain)
* [스파크라인 함수](/spreadjs/docs/v19/formulareference/FormulaFunctions/sparkline-functions)
* [`GC.Spread.Sheets.ConditionalFormatting.SparklineRule`](/spreadjs/docs/v19/)