거래 리포트 · 월간 명세
한 달치 거래를 요약하는 리포트를 만듭니다. 꺾은선·원·도넛 차트를 한 문서에서 쓰고, 숫자 서식과 자동 높이를 배웁니다.
여기서 배우는 것
편집기로 만들기
- 차트를 넣고 종류를 꺾은선으로 둡니다. 배열 경로 · 라벨 식 · 값 식 셋만 정하면 됩니다.
- 차트를 둘 더 넣어 원과 도넛으로 둡니다. 같은 배열을 다른 그림으로 읽는 것이므로 값 식은 그대로 둡니다.
- 원과 도넛은 비율을 보여주는 그림입니다. 항목이 여덟 개를 넘으면 조각이 얇아져 아무것도 못 읽으니, 그때는 막대로 바꾸십시오.
- 요약 숫자는 라벨로 씁니다. {{ format(sum(data.daily, "amount"), "number", "0,0", "ko-KR") }} 처럼 두면 표와 어긋나지 않습니다.
스키마 · API 로 만들기
- 차트는 chartKind 로 종류를 정합니다 — "bar"(기본) · "line" · "pie" · "donut".
- 데이터는 표와 같은 모양입니다 — bind 가 배열, columns[0].cell 이 라벨 식, columns[1].cell 이 값 식입니다. 새 키는 chartKind 하나뿐입니다.
- 값 식이 숫자가 아니면 그 조각은 0 입니다. 문자열이 오면 통화 서식이 NaN 을 내는 것과 같은 이유입니다 — 숫자를 보내십시오.
- format(값, "number", "0,0", 로케일) 로 자릿수를 넣습니다. 패턴을 비우면 0,0 이 기본입니다.
완성 문서
아래 JSON 이 위 두 순서가 만드는 바로 그 문서입니다. 저희 테스트가 이 문서를 검증하고 경고 없이 렌더되는지 확인하므로, 그대로 붙여 넣어 쓰셔도 됩니다.
{
"v": 1,
"unit": "px",
"page": {
"size": "a4",
"orientation": "portrait",
"margin": {
"t": 48,
"r": 48,
"b": 56,
"l": 48
},
"header": "{{ data.company }} · {{ data.period }}",
"footer": "[[page]] / [[pages]]"
},
"fonts": [],
"styles": [
{
"id": "s_h1",
"fontFamily": "Liberation Sans",
"fontSize": 22,
"fontWeight": 700,
"italic": false,
"color": "#111111",
"bg": "transparent",
"align": "left",
"valign": "top",
"lineHeight": 1.5,
"border": "none",
"radius": 0,
"opacity": 1
},
{
"id": "s_l",
"fontFamily": "Liberation Sans",
"fontSize": 12,
"fontWeight": 400,
"italic": false,
"color": "#333333",
"bg": "transparent",
"align": "left",
"valign": "top",
"lineHeight": 1.5,
"border": "none",
"radius": 0,
"opacity": 1
},
{
"id": "s_big",
"fontFamily": "Liberation Sans",
"fontSize": 28,
"fontWeight": 700,
"italic": false,
"color": "#111111",
"bg": "transparent",
"align": "left",
"valign": "top",
"lineHeight": 1.5,
"border": "none",
"radius": 0,
"opacity": 1
},
{
"id": "s_cap",
"fontFamily": "Liberation Sans",
"fontSize": 11,
"fontWeight": 400,
"italic": false,
"color": "#666666",
"bg": "transparent",
"align": "left",
"valign": "top",
"lineHeight": 1.5,
"border": "none",
"radius": 0,
"opacity": 1
}
],
"nodes": [
{
"id": "n_title",
"parent": "",
"order": 0,
"type": "label",
"x": 0,
"y": 0,
"w": 697,
"h": 28,
"show": "",
"styleId": "s_h1",
"props": {
"text": "Monthly statement",
"src": "",
"fit": "",
"thickness": 0,
"stroke": "",
"fill": "",
"repeat": "",
"as": "",
"break": "",
"keep": "",
"padding": 0,
"padY": 0,
"padX": 0,
"align": "",
"valign": "",
"wrap": "",
"bind": "",
"headerHeight": 0,
"rowHeight": 0,
"max": 0,
"columns": [],
"rows": 0,
"cells": [],
"chartKind": "",
"codeKind": "",
"ecc": "",
"fieldKind": "",
"fieldName": "",
"options": [],
"required": false,
"readonly": false,
"html": ""
},
"name": "Title"
},
{
"id": "n_sum",
"parent": "",
"order": 1,
"type": "label",
"x": 0,
"y": 40,
"w": 340,
"h": 36,
"show": "",
"styleId": "s_big",
"props": {
"text": "{{ format(sum(data.daily, \"amount\"), \"number\", \"0,0\", \"en-US\") }}",
"src": "",
"fit": "",
"thickness": 0,
"stroke": "",
"fill": "",
"repeat": "",
"as": "",
"break": "",
"keep": "",
"padding": 0,
"padY": 0,
"padX": 0,
"align": "",
"valign": "",
"wrap": "",
"bind": "",
"headerHeight": 0,
"rowHeight": 0,
"max": 0,
"columns": [],
"rows": 0,
"cells": [],
"chartKind": "",
"codeKind": "",
"ecc": "",
"fieldKind": "",
"fieldName": "",
"options": [],
"required": false,
"readonly": false,
"html": ""
},
"name": "Total"
},
{
"id": "n_sum_l",
"parent": "",
"order": 2,
"type": "label",
"x": 0,
"y": 78,
"w": 340,
"h": 0,
"show": "",
"styleId": "s_cap",
"props": {
"text": "Total this month",
"src": "",
"fit": "",
"thickness": 0,
"stroke": "",
"fill": "",
"repeat": "",
"as": "",
"break": "",
"keep": "",
"padding": 0,
"padY": 0,
"padX": 0,
"align": "",
"valign": "",
"wrap": "",
"bind": "",
"headerHeight": 0,
"rowHeight": 0,
"max": 0,
"columns": [],
"rows": 0,
"cells": [],
"chartKind": "",
"codeKind": "",
"ecc": "",
"fieldKind": "",
"fieldName": "",
"options": [],
"required": false,
"readonly": false,
"html": ""
},
"name": "Total caption"
},
{
"id": "n_line_l",
"parent": "",
"order": 3,
"type": "label",
"x": 0,
"y": 116,
"w": 697,
"h": 18,
"show": "",
"styleId": "s_l",
"props": {
"text": "Daily amount",
"src": "",
"fit": "",
"thickness": 0,
"stroke": "",
"fill": "",
"repeat": "",
"as": "",
"break": "",
"keep": "",
"padding": 0,
"padY": 0,
"padX": 0,
"align": "",
"valign": "",
"wrap": "",
"bind": "",
"headerHeight": 0,
"rowHeight": 0,
"max": 0,
"columns": [],
"rows": 0,
"cells": [],
"chartKind": "",
"codeKind": "",
"ecc": "",
"fieldKind": "",
"fieldName": "",
"options": [],
"required": false,
"readonly": false,
"html": ""
},
"name": "Line heading"
},
{
"id": "n_line",
"parent": "",
"order": 4,
"type": "chart",
"x": 0,
"y": 140,
"w": 697,
"h": 200,
"show": "",
"styleId": "s_l",
"props": {
"text": "",
"src": "",
"fit": "",
"thickness": 0,
"stroke": "",
"fill": "",
"repeat": "",
"as": "",
"break": "",
"keep": "",
"padding": 0,
"padY": 0,
"padX": 0,
"align": "",
"valign": "",
"wrap": "",
"bind": "data.daily",
"headerHeight": 0,
"rowHeight": 0,
"max": 0,
"columns": [
{
"header": "Day",
"cell": "{{ item.day }}",
"width": 0,
"align": "left"
},
{
"header": "Amount",
"cell": "{{ item.amount }}",
"width": 0,
"align": "right"
}
],
"rows": 0,
"cells": [],
"chartKind": "line",
"codeKind": "",
"ecc": "",
"fieldKind": "",
"fieldName": "",
"options": [],
"required": false,
"readonly": false,
"html": ""
},
"name": "Daily trend"
},
{
"id": "n_pie_l",
"parent": "",
"order": 5,
"type": "label",
"x": 0,
"y": 364,
"w": 340,
"h": 18,
"show": "",
"styleId": "s_l",
"props": {
"text": "Share by product group",
"src": "",
"fit": "",
"thickness": 0,
"stroke": "",
"fill": "",
"repeat": "",
"as": "",
"break": "",
"keep": "",
"padding": 0,
"padY": 0,
"padX": 0,
"align": "",
"valign": "",
"wrap": "",
"bind": "",
"headerHeight": 0,
"rowHeight": 0,
"max": 0,
"columns": [],
"rows": 0,
"cells": [],
"chartKind": "",
"codeKind": "",
"ecc": "",
"fieldKind": "",
"fieldName": "",
"options": [],
"required": false,
"readonly": false,
"html": ""
},
"name": "Pie heading"
},
{
"id": "n_pie",
"parent": "",
"order": 6,
"type": "chart",
"x": 0,
"y": 388,
"w": 340,
"h": 220,
"show": "",
"styleId": "s_l",
"props": {
"text": "",
"src": "",
"fit": "",
"thickness": 0,
"stroke": "",
"fill": "",
"repeat": "",
"as": "",
"break": "",
"keep": "",
"padding": 0,
"padY": 0,
"padX": 0,
"align": "",
"valign": "",
"wrap": "",
"bind": "data.mix",
"headerHeight": 0,
"rowHeight": 0,
"max": 0,
"columns": [
{
"header": "Group",
"cell": "{{ item.name }}",
"width": 0,
"align": "left"
},
{
"header": "Amount",
"cell": "{{ item.amount }}",
"width": 0,
"align": "right"
}
],
"rows": 0,
"cells": [],
"chartKind": "pie",
"codeKind": "",
"ecc": "",
"fieldKind": "",
"fieldName": "",
"options": [],
"required": false,
"readonly": false,
"html": ""
},
"name": "Share pie"
},
{
"id": "n_donut_l",
"parent": "",
"order": 7,
"type": "label",
"x": 357,
"y": 364,
"w": 340,
"h": 18,
"show": "",
"styleId": "s_l",
"props": {
"text": "Share by channel",
"src": "",
"fit": "",
"thickness": 0,
"stroke": "",
"fill": "",
"repeat": "",
"as": "",
"break": "",
"keep": "",
"padding": 0,
"padY": 0,
"padX": 0,
"align": "",
"valign": "",
"wrap": "",
"bind": "",
"headerHeight": 0,
"rowHeight": 0,
"max": 0,
"columns": [],
"rows": 0,
"cells": [],
"chartKind": "",
"codeKind": "",
"ecc": "",
"fieldKind": "",
"fieldName": "",
"options": [],
"required": false,
"readonly": false,
"html": ""
},
"name": "Donut heading"
},
{
"id": "n_donut",
"parent": "",
"order": 8,
"type": "chart",
"x": 357,
"y": 388,
"w": 340,
"h": 220,
"show": "",
"styleId": "s_l",
"props": {
"text": "",
"src": "",
"fit": "",
"thickness": 0,
"stroke": "",
"fill": "",
"repeat": "",
"as": "",
"break": "",
"keep": "",
"padding": 0,
"padY": 0,
"padX": 0,
"align": "",
"valign": "",
"wrap": "",
"bind": "data.channel",
"headerHeight": 0,
"rowHeight": 0,
"max": 0,
"columns": [
{
"header": "Channel",
"cell": "{{ item.name }}",
"width": 0,
"align": "left"
},
{
"header": "Amount",
"cell": "{{ item.amount }}",
"width": 0,
"align": "right"
}
],
"rows": 0,
"cells": [],
"chartKind": "donut",
"codeKind": "",
"ecc": "",
"fieldKind": "",
"fieldName": "",
"options": [],
"required": false,
"readonly": false,
"html": ""
},
"name": "Share donut"
}
]
}요청 본문입니다. template 자리에 위 문서를, data 자리에 아래 데이터를 넣습니다.
{
"template": "(the document above)",
"data": {
"company": "brewmypdf",
"period": "2026-08",
"daily": [
{
"day": "1",
"amount": 1200
},
{
"day": "8",
"amount": 1850
},
{
"day": "15",
"amount": 1400
},
{
"day": "22",
"amount": 2100
},
{
"day": "29",
"amount": 1650
}
],
"mix": [
{
"name": "Subscription",
"amount": 4200
},
{
"name": "One-off",
"amount": 2600
},
{
"name": "Consulting",
"amount": 1400
}
],
"channel": [
{
"name": "Direct",
"amount": 5100
},
{
"name": "Partner",
"amount": 3100
}
]
}
}