# 도형 속성 수식

## Content

SpreadJS는 워크시트에 수식이 포함된 기본 도형 및 사용자 정의 도형을 추가하여 도형 모델을 수정할 수 있도록 지원합니다.

## 데이터 기반 도형을 사용하는 이점

이 기능을 사용하면 사용자가 스프레드시트, 다른 도형 또는 데이터 원본의 수식을 통해 속성이 평가되는 동적 도형을 생성할 수 있습니다. 이를 통해 도형 데이터를 이러한 수식과 바인딩할 수 있습니다.
아래는 이 기능이 특히 유용한 몇 가지 시나리오입니다:

* 사용자가 스프레드시트의 수식을 기반으로 동적으로 업데이트되는 순서도를 생성하고자 할 때
* 사용자가 동일한 직급의 직원에 대해 동일한 배경 도형을 유지하면서 회사 직원의 계층 차트를 관리하고자 할 때
* 사용자가 스프레드시트에서 값이 업데이트될 때마다 도형 내의 매출 수치를 업데이트하고자 할 때

수식이 포함된 도형을 추가하려면 다음 작업을 참조하시기 바랍니다:

* [수식이 포함된 기본 도형 추가](/spreadjs/docs/features/UnderstandingShapes/AddingShapeswithFormulas#수식이-포함된-기본-도형-추가)
* [수식이 포함된 사용자 정의 도형 추가](/spreadjs/docs/features/UnderstandingShapes/AddingShapeswithFormulas#수식이-포함된-사용자-정의-도형-추가)

## 수식이 포함된 기본 도형 추가

사용자는 워크시트에 수식이 포함된 기본 도형을 추가할 수 있습니다. 아래는 기본 수식으로 생성된 도형의 예입니다.
![](https://gcdocumentsitekrblob.blob.core.windows.net/document-site-files/images/8d606653-16a0-474d-b9dc-e2b4d01c2446/images/formulabuiltshape.png)

아래의 코드 샘플은 워크시트에 수식이 포함된 기본 도형을 추가하는 방법을 보여줍니다.

```javascript
 //수식이 포함된 기본 도형 추가
 window.onload = function ()
{
  var spread = new GC.Spread.Sheets.Workbook(document.getElementById("ss"));
  var sheet = spread.getActiveSheet();
  sheet.name("BuiltInShape");
  sheet.setArray(0, 0, [
  ["x", 430], ["y", 25],
  ["width", 280], ["height", 160],
  ["angle", 0], ["background color and tranparency", "green", 0.5],
  ["border color and width", "blue", 0],
  ["shape text", "The demo text for built-in shape"],
  ["text font", "18px Georgia"],
  ["text color", "white"],
  ]);
  sheet.setColumnWidth(0, 220);
  sheet.setColumnWidth(1, 100);
  sheet.setColumnWidth(2, 70);
  sheet.setColumnWidth(3, 70);
  sheet.setColumnWidth(4, 70);
  sheet.setColumnWidth(5, 70);;
  var shape1 = sheet.shapes.add("shape1",
  GC.Spread.Sheets.Shapes.AutoShapeType.oval, 100, 50, 100, 150);
  shape1.x("=BuiltInShape!B1");
  shape1.y("=BuiltInShape!B2");
  shape1.width("=BuiltInShape!B3");
  shape1.height("=BuiltInShape!B4");
  shape1.rotate("=BuiltInShape!B5");
  shape1.text("=BuiltInShape!B8");
  var shape1Style = shape1.style();
  shape1Style.fill.color = "=BuiltInShape!B6";
  shape1Style.fill.transparency = "=BuiltInShape!C6";
  shape1Style.line.color = "=BuiltInShape!B7";
  shape1Style.line.transparency = "=BuiltInShape!C7";
  shape1Style.textEffect.font = "=BuiltInShape!B9";
  shape1Style.textEffect.color = "=BuiltInShape!B10";
  shape1.style(shape1Style);
 };
```

사용자는 도형의 속성에 대해 정의된 수식뿐만 아니라 해당 속성에 대해 수식이 참조하는 값을 얻을 수 있습니다. 예를 들어 위 기본 도형에서 높이에 대한 수식은 `=BuiltInShape!B4`로 정의되며, 해당 셀(B4)에는 `160`이라는 값이 있습니다.
아래 코드 샘플은 [getFormula](/spreadjs/api/classes/GC.Spread.Sheets.Worksheet#getFormula) 메서드를 사용하여 속성에 대한 수식을 가져오고 해당 속성의 값을 가져오는 방법을 보여줍니다.

```javascript
// 활성 시트 가져오기
var activeSheet = spread.getSheet(0);
activeSheet.setArray(0, 0, [
    ["x", 10],
    ["y", 200],
    ["width", 300],
    ["height", 140],
    ["angle", 0],
    ["background color and tranparency", "red", 0.5],
    ["border color and width", "blue", 5],
    ["shape text", "The demo text for cloud shape"],
    ["text font", "15px Georgia"],
    ["text color", "Yellow"],
]);

var shape1 = activeSheet.shapes.add("shape1", GC.Spread.Sheets.Shapes.AutoShapeType.cloud, 50, 200, 100, 150);
var shapeStyle = shape1.style();
shapeStyle.fill.color = '=Sheet1!B6';
shape1.style(shapeStyle);

// setFormula() 메서드로 속성 설정
shape1.setFormula("x", "=Sheet1!B1");
shape1.setFormula("y", "=Sheet1!B2");
shape1.setFormula("width", "=Sheet1!B3");
shape1.setFormula("height", "=Sheet1!B4");
shape1.setFormula("rotate", "=Sheet1!B5");
shape1.setFormula("text", "=Sheet1!B8");
shape1.setFormula("style.fill.color", "=Sheet1!B6");
shape1.setFormula("style.fill.transparency", "=Sheet1!C6");
shape1.setFormula("style.line.color", "=Sheet1!B7");
shape1.setFormula("style.line.width", "=Sheet1!C7");
shape1.setFormula("style.textEffect.font", "=Sheet1!B9");
shape1.setFormula("style.textEffect.color", "=Sheet1!B10");

// getFormula() 메서드로 수식 가져오기
console.log("Formula for Width : " + shape1.getFormula("width"));
console.log("Formula for Height : " + shape1.getFormula("height"));

// 속성으로 값 확인
console.log("Value of Width: ", shape1.width());
console.log("Value of Height: ", shape1.height());

activeSheet.setColumnWidth(0, 280);
activeSheet.setColumnWidth(1, 100);
for (var i = 2; i < 8; i++)
    activeSheet.setColumnWidth(i, 70);
```

## 수식이 포함된 사용자 정의 도형 추가

사용자는 시트에 수식이 포함된 사용자 정의 도형을 추가할 수 있습니다. 아래 이미지는 사용자 정의 수식으로 생성된 도형 예시입니다.

![](https://gcdocumentsitekrblob.blob.core.windows.net/document-site-files/images/8d606653-16a0-474d-b9dc-e2b4d01c2446/images/shape_customformula.png)

아래의 코드 샘플은 시트에 수식이 포함된 도형을 추가하는 방법을 보여줍니다.

```javascript
// 수식이 포함된 도형 추가
window.onload = function ()
{
   var spread = new GC.Spread.Sheets.Workbook(document.getElementById("ss"));
   var sheet = spread.getActiveSheet();
   sheet.name("CustomShape");
   sheet.setArray(0, 0, [
       ["left", 480], ["top", 60], ["width", 400], ["height", 240],["angle"],
       ["background color and tranparency", "green", 0.5],
       ["border color and width", "blue", 0],
       ["shape text", "The demo text for custom shape"],
       ["text font", "15px Georgia"],
       ["text color", "red"],
       ["margins", 1, 2, 3, 4],
       ["horizontalAlignment", 1],
       ["verticalAlignment", 1],
       ["textDirection", "horizontal"],
       ["allowTextToOverflowShape", false],
       ["wrapTextInShape", true],
       ["line width", 3],
       ["line style", 5, "capType", 2, "joinType", 1],
       ["endPoints", 1, 1, 1, 5, 2, 2],
   ]);
   sheet.setColumnWidth(0, 280);
   sheet.setColumnWidth(1, 100);
   sheet.setColumnWidth(2, 70);
   sheet.setColumnWidth(3, 70);
   sheet.setColumnWidth(4, 70);
   sheet.setColumnWidth(5, 70);
   sheet.setCellType(11, 1,
   createComboCellType(GC.Spread.Sheets.HorizontalAlign, 2));
   sheet.setCellType(12, 1, createComboCellType(GC.Spread.Sheets.VerticalAlign));
   sheet.setCellType(17, 1,
   createComboCellType(GC.Spread.Sheets.Shapes.PresetLineDashStyle));
   sheet.setCellType(17, 3, createComboCellType(GC.Spread.Sheets.Shapes.LineCapStyle));
   sheet.setCellType(17, 5,
   createComboCellType(GC.Spread.Sheets.Shapes.LineJoinStyle));
   sheet.setCellType(18, 1,
   createComboCellType(GC.Spread.Sheets.Shapes.ArrowheadStyle));
   sheet.setCellType(18, 4,
   createComboCellType(GC.Spread.Sheets.Shapes.ArrowheadStyle));
   sheet.setCellType(18, 2,
   createComboCellType(GC.Spread.Sheets.Shapes.ArrowheadLength));
   sheet.setCellType(18, 5,
   createComboCellType(GC.Spread.Sheets.Shapes.ArrowheadLength));
   sheet.setCellType(18, 3,
   createComboCellType(GC.Spread.Sheets.Shapes.ArrowheadWidth));
   sheet.setCellType(18, 6,
   createComboCellType(GC.Spread.Sheets.Shapes.ArrowheadWidth));
   sheet.setFormula(4, 1, "=ROW(CustomShape!B10)");
var model =
{
    left: "=CustomShape!B1",
    top: "=CustomShape!B2",
    width: "=CustomShape!B3",
    height: "=CustomShape!B4",
    angle: "=CustomShape!B5",
    options: {
        endPoints: {
        beginArrow:
        {
            type: "=CustomShape!B19", widthType:
            "=CustomShape!C19", lengthType: "=CustomShape!D19"
        },
        endArrow: { type: "=CustomShape!E19", widthType:
        "=CustomShape!F19", lengthType: "=CustomShape!G19" }
        },
        fill:
        {
        type: 1, // 단색 채우기 (현재는 단색 채우기만 지원)
        color: "=CustomShape!B6",
        transparency: "=CustomShape!C6"
        },
        stroke:
        {
        type: 1, // 단색 채우기 (현재는 단색 채우기만 지원)
        color: "=CustomShape!B7",
        transparency: "=CustomShape!C7",
        width: "=CustomShape!B17",
        lineStyle: "=CustomShape!B18",
        capType: "=CustomShape!D18",
        joinType: "=CustomShape!F18"
        },
        textFormatOptions:
        {
            text: "=CustomShape!B8", // "도형 텍스트",
            font: "=CustomShape!B9", // "bold 15px Georgia
            fill:
            {
                type: 1, // 단색 채우기 (현재는 단색 채우기만 지원)
                color: "=CustomShape!B10"
            },
            margins:
            {
                left: "=CustomShape!B11",
                top: "=CustomShape!C11",
                right: "=CustomShape!D11",
                bottom: "=CustomShape!E11"
            },
            verticalAlignment:
            "=CustomShape!B13",  // (0: top, 1: center, 2: bottom)
            horizontalAlignment:
            "=CustomShape!B12", // (0: left, 1: center, 2: right)
            textDirection:
            "=CustomShape!B14", //f "vertical", "rotate90", "rotate270"
            allowTextToOverflowShape: "=CustomShape!B15",
            wrapTextInShape: "=CustomShape!B16"
        }
    },
    variables: {
        xOffset: 40,
        yOffset: 10
    },
    path: [[
            ["M", "=controls.0.x", 0],          // M: 좌표 (x, y)으로 이동
            ["L", "=width - controls.0.x", 0],  // L: 좌표 (x, y)까지 선을 그림
            ["L", "=width - 2 * variables.xOffset", "=height"], ["L", "=variables.xOffset", "=height"],
            ["Z"]
        ],  // Z: 경로 닫기
        [
            ["M", "=width - variables.xOffset", "=variables.yOffset"],
            ["L", "=width", "=variables.yOffset"],
            ["L", "=width", "=height - 4 * variables.yOffset"],
            ["L", "=width - variables.xOffset", "=height"]
        ]
    ],
    controls: [
        {
            x: "=BOUND(0.3*width, 0, false, 0, 0.5*width)",// → 위치 및 범위 제한을 제공하기 위한 수식 사용 (여기서는 기본 위치가 (0, 너비의 0.2)이며, y 범위는 0부터 너비의 0.5까지)
            y: 0,
            xBehavior: 0,  //  x 방향으로 조정 시 0 (수평 방향), 그렇지 않으면 1
            yBehavior: 1   // y 방향으로 조정 시 0 (수직 방향), 그렇지 않으면 1
        }
    ],
    connectionPoints: [
        {
            x: "=0.5*width",
            y: 0
        },
        {
            x: "=0.5*controls.0.x",
            y: "=0.5*height"
        },
        {
            x: "=0.5*width",
            y: "=1*height"
        },
        {
            x: "=width-0.5*controls.0.x",
            y: "=0.5*height"
        }
    ],
    textRect:
    { left: "=controls.0.x", top: 20, bottom: "=height - 20",
    right: "=width - variables.xOffset" }};
    sheet.shapes.add('shape2', model);
};
function createComboCellType(enumType, max)
{
    var combo = new GC.Spread.Sheets.CellTypes.ComboBox();
    var items = [];
    for (var name in enumType)
    {
        var value = enumType[name];
        if (!max || value <= max)
        {
            items.push
            ({
                text: name,
                value: value
            });
        }
    }
    combo.items(items);
    combo.editorValueType(GC.Spread.Sheets.CellTypes.EditorValueType.value);
    return combo;
}
```

>type=warning
> **참고:** Shape API 세트는 사용자 정의 옵션처럼 수식 또는 값을 모두 허용하지만, 항상 해당 속성의 값을 반환합니다. A1 스타일을 사용할 경우 `sheetName!A10` 형식의 범위 참조가 필요하며, `ROW(Sheet1!B30)`과 같은 컨텍스트 의존 수식도 지원됩니다.

사용자는 도형의 속성에 대해 정의된 수식뿐만 아니라, 해당 수식이 참조하는 값을 가져올 수도 있습니다. 예를 들어, 위 사용자 정의 도형에서는 도형의 높이(height) 속성에 대한 수식이 `"=CustomShape!B4"`로 정의되어 있으며, B4 셀에는 높이 값으로 240이 설정되어 있습니다.
다음 코드 샘플은 [getFormula](/spreadjs/api/classes/GC.Spread.Sheets.Worksheet#getFormula) 메서드를 사용하여 사용자 정의 도형의 속성에 설정된 수식과 값을 가져오는 방법을 보여줍니다.

```javascript
// 활성 시트를 가져옴
var activeSheet = spread.getSheet(0);
activeSheet.name("CustomShape");
// 데이터 설정
activeSheet.setArray(0, 0, [
    ["left", 480],
    ["top", 60],
    ["width", 300],
    ["height", 240],
    ["angle"],
    ["background color and tranparency", "green", 0.5],
    ["border color and width", "blue", 0],
    ["shape text", "The demo text for custom shape"],
    ["text font", "15px Georgia"],
    ["text color", "red"],
    ["margins", 1, 2, 3, 4],
    ["horizontalAlignment", 1],
    ["verticalAlignment", 1],
    ["textDirection", "horizontal"],
    ["allowTextToOverflowShape", false],
    ["wrapTextInShape", true],
    ["line width", 3],
    ["line style", 5, "capType", 2, "joinType", 1],
    ["endPoints", 1, 1, 1, 5, 2, 2],
]);
activeSheet.setFormula(4, 1, "=ROW(CustomShape!B10)");
var model = {
    left: "=CustomShape!B1",
    top: "=CustomShape!B2",
    width: "=CustomShape!B3",
    height: "=CustomShape!B4",
    angle: "=CustomShape!B5",
    options: {
        endPoints: {
            beginArrow: {
                type: "=CustomShape!B19", widthType: "=CustomShape!C19", lengthType: "=CustomShape!D19"
            },
            endArrow: { type: "=CustomShape!E19", widthType: "=CustomShape!F19", lengthType: "=CustomShape!G19" }
        },
        fill: {
            type: 1, // 단색 채우기 (현재는 단색 채우기만 지원)
            color: "=CustomShape!B6",
            transparency: "=CustomShape!C6"
        },
        stroke: {
            type: 1, // 단색 채우기 (현재는 단색 채우기만 지원)
            color: "=CustomShape!B7",
            transparency: "=CustomShape!C7",
            width: "=CustomShape!B17",
            lineStyle: "=CustomShape!B18",
            capType: "=CustomShape!D18",
            joinType: "=CustomShape!F18"
        },
        textFormatOptions: {
            text: "=CustomShape!B8", // "도형 텍스트",
            font: "=CustomShape!B9", // "bold 15px Georgia",  // CSS 글꼴 및 줌 관련 코드는 이를 지원하도록 업데이트되어야 합니다
            fill: {
                type: 1, // 단색 채우기 (현재는 단색 채우기만 지원)
                color: "=CustomShape!B10"
            },
            margins: {
                left: "=CustomShape!B11",
                top: "=CustomShape!C11",
                right: "=CustomShape!D11",
                bottom: "=CustomShape!E11"
            },
            verticalAlignment: "=CustomShape!B13",  // (0: top, 1: center, 2: bottom)
            horizontalAlignment: "=CustomShape!B12", // (0: left, 1: center, 2: right)
            textDirection: "=CustomShape!B14", //f "vertical", "rotate90", "rotate270"
            allowTextToOverflowShape: "=CustomShape!B15",
            wrapTextInShape: "=CustomShape!B16"
        }
    },
    variables: {
        xOffset: 40,
        yOffset: 10
    },
    path: [[
        ["M", "=controls.0.x", 0],          // M: 좌표 (x, y)으로 이동
        ["L", "=width - controls.0.x", 0],  // L: 좌표 (x, y)까지 선을 그림
        ["L", "=width - 2 * variables.xOffset", "=height"], ["L", "=variables.xOffset", "=height"],
        ["Z"]],  // Z: 경로 닫기 
    [
        ["M", "=width - variables.xOffset", "=variables.yOffset"],
        ["L", "=width", "=variables.yOffset"],
        ["L", "=width", "=height - 4 * variables.yOffset"],
        ["L", "=width - variables.xOffset", "=height"]
    ]
    ],
    controls: [
        {
            // 포지션 및 범위 제한용 수식 사용 (기본 위치 (0, 0.3 * width), y 범위는 0 ~ 0.5 * width)
            x: "=BOUND(0.3*width, 0, false, 0, 0.5*width)",
            y: 0,
            xBehavior: 0,  //  x 방향으로 조정 시 0 (수평 방향), 그렇지 않으면 1
            yBehavior: 1   // y 방향으로 조정 시 0 (수직 방향), 그렇지 않으면 1
        }
    ],
    connectionPoints: [
        {
            x: "=0.5*width",
            y: 0
        },
        {
            x: "=0.5*controls.0.x",
            y: "=0.5*height"
        },
        {
            x: "=0.5*width",
            y: "=1*height"
        },
        {
            x: "=width-0.5*controls.0.x",
            y: "=0.5*height"
        }
    ],
    textRect: { left: "=controls.0.x", top: 20, bottom: "=height - 20", right: "=width - variables.xOffset" }
};
var shape2 = activeSheet.shapes.add('shape2', model);

// getFormula() 메서드를 사용해 width와 height 속성에 지정된 수식 가져오기
console.log("Width's Formula is: " + shape2.getFormula("width"));
console.log("Height's Formula is: " + shape2.getFormula("height"));

// 속성 메서드를 사용해 실제 width와 height 값 가져오기
console.log("Width value ", shape2.width());
console.log("Height value ", shape2.height());


// 열 너비 설정
activeSheet.setColumnWidth(0, 210);
activeSheet.setColumnWidth(1, 60);
for (var i = 2; i < 6; i++) {
    activeSheet.setColumnWidth(i, 50);
}
```