@guandata/guanvis 0.1.28 → 0.1.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +15 -0
- package/LICENSE +133 -0
- package/LICENSE.zh-CN +82 -0
- package/README.md +15 -0
- package/binaries/guanvis-darwin-arm64 +0 -0
- package/binaries/guanvis-darwin-x64 +0 -0
- package/binaries/guanvis-linux-arm64 +0 -0
- package/binaries/guanvis-linux-x64 +0 -0
- package/binaries/guanvis-win32-x64.exe +0 -0
- package/package.json +4 -2
- package/skills/guanvis/SKILL.md +32 -11
- package/skills/guanvis/evals/dynamic_fields/card_01_dynamic_dataset.js +20 -0
- package/skills/guanvis/evals/dynamic_fields/card_02_dynamic_metric_chart.js +16 -0
- package/skills/guanvis/evals/dynamic_fields/metrics.js +19 -0
- package/skills/guanvis/evals/dynamic_fields/page.js +9 -0
- package/skills/guanvis/evals/dynamic_fields/schema.js +7 -0
- package/skills/guanvis/evals/dynamic_fields/verify_default_roundtrip.sh +137 -0
- package/skills/guanvis/evals/split_charts/card_01_column_split.js +10 -0
- package/skills/guanvis/evals/split_charts/card_02_line_split.js +10 -0
- package/skills/guanvis/evals/split_charts/card_03_combo_split.js +11 -0
- package/skills/guanvis/evals/split_charts/page.js +10 -0
- package/skills/guanvis/evals/split_charts/schema.js +14 -0
- package/skills/guanvis/evals/tab_layout/card_03_story.js +2 -2
- package/skills/guanvis/evals/tab_layout/page.js +1 -1
- package/skills/guanvis/references/api-reference.md +22 -1
- package/skills/guanvis/references/builder-reference.md +164 -19
- package/skills/guanvis/references/metric-chart-reference.md +40 -0
- package/skills/guanvis/references/publish-and-constraints.md +6 -5
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
ROOT_DIR="$(cd "$(dirname "$0")/../.." && pwd)"
|
|
5
|
+
EVAL_DIR="$ROOT_DIR/evals/dynamic_fields"
|
|
6
|
+
OUT_DIR="$EVAL_DIR/.roundtrip"
|
|
7
|
+
|
|
8
|
+
mkdir -p "$OUT_DIR"
|
|
9
|
+
|
|
10
|
+
cd "$ROOT_DIR"
|
|
11
|
+
|
|
12
|
+
go run ./cmd/guanvis preview "$EVAL_DIR" > "$OUT_DIR/preview_payload.json"
|
|
13
|
+
go run ./cmd/guanvis pack "$EVAL_DIR" -o "$OUT_DIR/dynamic_fields_package.zip" > "$OUT_DIR/pack.log"
|
|
14
|
+
|
|
15
|
+
if [[ "${PUBLISH:-0}" == "1" ]]; then
|
|
16
|
+
go run ./cmd/guanvis publish "$EVAL_DIR" > "$OUT_DIR/publish.log"
|
|
17
|
+
guancli card get dfcarddataset00000000000 --raw > "$OUT_DIR/raw_dataset_card.json"
|
|
18
|
+
guancli card get dfmetriccard000000000000 --raw > "$OUT_DIR/raw_metric_card.json"
|
|
19
|
+
fi
|
|
20
|
+
|
|
21
|
+
python3 - "$OUT_DIR" <<'PY'
|
|
22
|
+
import json
|
|
23
|
+
import sys
|
|
24
|
+
from pathlib import Path
|
|
25
|
+
|
|
26
|
+
out = Path(sys.argv[1])
|
|
27
|
+
|
|
28
|
+
expected = {
|
|
29
|
+
"dfcarddataset00000000000": {
|
|
30
|
+
"name": "动态维度与动态数值",
|
|
31
|
+
"mappings": {
|
|
32
|
+
"分析维度": {"zoneId": "row", "metaType": "DIM", "multiSelect": False},
|
|
33
|
+
"分析数值": {"zoneId": "metric", "metaType": "METRIC", "multiSelect": True},
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
"dfmetriccard000000000000": {
|
|
37
|
+
"name": "指标平台动态维度与动态指标",
|
|
38
|
+
"mappings": {
|
|
39
|
+
"分析维度": {"zoneId": "row", "metaType": "DIM", "multiSelect": False},
|
|
40
|
+
"分析指标": {"zoneId": "metric", "metaType": "METRIC", "multiSelect": True},
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
def load_json(path):
|
|
46
|
+
text = path.read_text(encoding="utf-8")
|
|
47
|
+
start = text.find("{")
|
|
48
|
+
if start > 0:
|
|
49
|
+
text = text[start:]
|
|
50
|
+
return json.loads(text)
|
|
51
|
+
|
|
52
|
+
def normalize_card(raw):
|
|
53
|
+
obj = raw.get("response") or raw.get("data") or raw
|
|
54
|
+
if "card" in obj:
|
|
55
|
+
card = obj["card"]
|
|
56
|
+
meta = json.loads(card["meta"]) if isinstance(card.get("meta"), str) else card.get("meta")
|
|
57
|
+
return {"id": card.get("cdId"), "name": card.get("name"), "meta": meta}
|
|
58
|
+
content = obj.get("content") or obj
|
|
59
|
+
return {"id": obj.get("cdId") or obj.get("id"), "name": obj.get("name"), "meta": content.get("meta")}
|
|
60
|
+
|
|
61
|
+
def preview_cards():
|
|
62
|
+
payload = load_json(out / "preview_payload.json")
|
|
63
|
+
cards = []
|
|
64
|
+
for item in payload.get("cards", []):
|
|
65
|
+
card = item.get("card", {})
|
|
66
|
+
meta = json.loads(card["meta"]) if isinstance(card.get("meta"), str) else card.get("meta")
|
|
67
|
+
cards.append({"id": card.get("cdId"), "name": card.get("name"), "meta": meta})
|
|
68
|
+
return cards
|
|
69
|
+
|
|
70
|
+
def assert_dynamic_card(card):
|
|
71
|
+
card_id = card["id"]
|
|
72
|
+
if card_id not in expected:
|
|
73
|
+
return None
|
|
74
|
+
spec = expected[card_id]
|
|
75
|
+
chart_main = (card.get("meta") or {}).get("chartMain") or {}
|
|
76
|
+
zone_data = chart_main.get("zoneData") or {}
|
|
77
|
+
dz_info = chart_main.get("dynamicZoneInfo") or {}
|
|
78
|
+
if dz_info.get("hidden") is not False:
|
|
79
|
+
raise SystemExit(f"{card_id}: dynamicZoneInfo.hidden={dz_info.get('hidden')!r}, want false")
|
|
80
|
+
mappings = dz_info.get("dzMappings") or []
|
|
81
|
+
by_name = {m.get("name"): m for m in mappings}
|
|
82
|
+
if set(by_name) != set(spec["mappings"]):
|
|
83
|
+
raise SystemExit(f"{card_id}: dzMappings names={sorted(by_name)}, want {sorted(spec['mappings'])}")
|
|
84
|
+
|
|
85
|
+
summary = {"cardId": card_id, "name": card.get("name"), "mappings": {}}
|
|
86
|
+
for name, want in spec["mappings"].items():
|
|
87
|
+
mapping = by_name[name]
|
|
88
|
+
for key, want_value in want.items():
|
|
89
|
+
got = mapping.get(key)
|
|
90
|
+
if got != want_value:
|
|
91
|
+
raise SystemExit(f"{card_id}: mapping {name} {key}={got!r}, want {want_value!r}")
|
|
92
|
+
if mapping.get("selectType") != "SEARCHBOX":
|
|
93
|
+
raise SystemExit(f"{card_id}: mapping {name} selectType={mapping.get('selectType')!r}, want SEARCHBOX")
|
|
94
|
+
if mapping.get("orderType") not in ("PRESET", "CLICK"):
|
|
95
|
+
raise SystemExit(f"{card_id}: mapping {name} invalid orderType={mapping.get('orderType')!r}")
|
|
96
|
+
dz_id = mapping.get("dzId")
|
|
97
|
+
defaults = mapping.get("defaultValue") or []
|
|
98
|
+
if not dz_id:
|
|
99
|
+
raise SystemExit(f"{card_id}: mapping {name} missing dzId")
|
|
100
|
+
if not defaults:
|
|
101
|
+
raise SystemExit(f"{card_id}: mapping {name} defaultValue is empty")
|
|
102
|
+
zone_fields = zone_data.get(mapping["zoneId"]) or []
|
|
103
|
+
candidate_keys = {f.get("key") for f in zone_fields if f.get("dzId") == dz_id}
|
|
104
|
+
if not candidate_keys:
|
|
105
|
+
raise SystemExit(f"{card_id}: mapping {name} has no zoneData candidates for dzId={dz_id}")
|
|
106
|
+
missing = [key for key in defaults if key not in candidate_keys]
|
|
107
|
+
if missing:
|
|
108
|
+
raise SystemExit(f"{card_id}: mapping {name} defaultValue keys {missing} not found in zoneData.{mapping['zoneId']}")
|
|
109
|
+
summary["mappings"][name] = {
|
|
110
|
+
"dzId": dz_id,
|
|
111
|
+
"zoneId": mapping["zoneId"],
|
|
112
|
+
"metaType": mapping["metaType"],
|
|
113
|
+
"multiSelect": mapping["multiSelect"],
|
|
114
|
+
"defaultValue": defaults,
|
|
115
|
+
"candidateCount": len(candidate_keys),
|
|
116
|
+
}
|
|
117
|
+
return summary
|
|
118
|
+
|
|
119
|
+
summaries = []
|
|
120
|
+
for card in preview_cards():
|
|
121
|
+
result = assert_dynamic_card(card)
|
|
122
|
+
if result:
|
|
123
|
+
summaries.append(result)
|
|
124
|
+
|
|
125
|
+
if len(summaries) != len(expected):
|
|
126
|
+
got = sorted(item["cardId"] for item in summaries)
|
|
127
|
+
raise SystemExit(f"preview dynamic card count={len(summaries)}, got {got}, want {sorted(expected)}")
|
|
128
|
+
|
|
129
|
+
if (out / "raw_dataset_card.json").exists() and (out / "raw_metric_card.json").exists():
|
|
130
|
+
for raw_name in ("raw_dataset_card.json", "raw_metric_card.json"):
|
|
131
|
+
raw_summary = assert_dynamic_card(normalize_card(load_json(out / raw_name)))
|
|
132
|
+
summaries.append({**raw_summary, "source": raw_name})
|
|
133
|
+
|
|
134
|
+
summary = {"cards": summaries}
|
|
135
|
+
(out / "summary.json").write_text(json.dumps(summary, ensure_ascii=False, indent=2), encoding="utf-8")
|
|
136
|
+
print(json.dumps(summary, ensure_ascii=False, indent=2))
|
|
137
|
+
PY
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
var card = createCard(ChartType.BASIC_COLUMN, "按产品拆分区域营收")
|
|
2
|
+
.setId("spcolsplitdemoaabbccddee")
|
|
3
|
+
.bindDataset(DS)
|
|
4
|
+
.addRow(f("区域"))
|
|
5
|
+
.addMetric(f("营收", { aggrType: AggrType.SUM, numberFormat: NumberFormat.currency("¥", 0) }))
|
|
6
|
+
.addSplit(f("产品"))
|
|
7
|
+
.setSplitSetting({ rows: 2, columns: 3 })
|
|
8
|
+
.setDataLabel({ show: true, showNumber: true });
|
|
9
|
+
|
|
10
|
+
registerCard(card.build());
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
var card = createCard(ChartType.BASIC_LINE, "按产品拆分月营收趋势")
|
|
2
|
+
.setId("splinesplitdemoaabbccdde")
|
|
3
|
+
.bindDataset(DS)
|
|
4
|
+
.addRow(f("月份", { granularity: "MONTH" }))
|
|
5
|
+
.addMetric(f("营收", { aggrType: AggrType.SUM, numberFormat: NumberFormat.currency("¥", 0) }))
|
|
6
|
+
.addSplit(f("产品"))
|
|
7
|
+
.setSplitSetting({ rows: 2, columns: 3 })
|
|
8
|
+
.setShowLegend(false);
|
|
9
|
+
|
|
10
|
+
registerCard(card.build());
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
var card = createCard(ChartType.GROUPED_COLUMN_WITH_LINE, "按产品拆分营收成本趋势")
|
|
2
|
+
.setId("spcombosplitdemoaabbccdd")
|
|
3
|
+
.bindDataset(DS)
|
|
4
|
+
.addRow(f("月份", { granularity: "MONTH" }))
|
|
5
|
+
.addMetric(f("营收", { aggrType: AggrType.SUM, numberFormat: NumberFormat.currency("¥", 0) }))
|
|
6
|
+
.addMetricAdditional(f("成本", { aggrType: AggrType.SUM, numberFormat: NumberFormat.currency("¥", 0) }))
|
|
7
|
+
.addSplit(f("产品"))
|
|
8
|
+
.setSplitSetting({ rows: 2, columns: 2 })
|
|
9
|
+
.setShowLegend(true, "bottom");
|
|
10
|
+
|
|
11
|
+
registerCard(card.build());
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
var page = createPage("拆分图示例")
|
|
2
|
+
.setId("sppagesplitdemoaabbccdde")
|
|
3
|
+
.setDescription("展示柱形、折线和柱线组合图的 addSplit 用法。")
|
|
4
|
+
.setBackgroundColor("#f5f5f5")
|
|
5
|
+
.setCardMargin(8)
|
|
6
|
+
.addFullWidthCard(0, 6)
|
|
7
|
+
.addFullWidthCard(1, 6)
|
|
8
|
+
.addFullWidthCard(2, 6);
|
|
9
|
+
|
|
10
|
+
registerPage(page.build());
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// Auto-generated by guanvis schema command
|
|
2
|
+
// DO NOT EDIT — regenerate with: guanvis schema s9ded2338f43807b095fbb4f
|
|
3
|
+
// This file defines dataset schemas for field() references in card scripts.
|
|
4
|
+
|
|
5
|
+
// Dataset: 销售数据 (example, 7 fields)
|
|
6
|
+
defineDataset("s9ded2338f43807b095fbb4f", [
|
|
7
|
+
{ fdId: "jb16f22f6c1c21c3f6e8e293", name: "区域", fdType: "STRING", metaType: "DIM" },
|
|
8
|
+
{ fdId: "o7093aaf2b2f32c9e964c41a", name: "产品", fdType: "STRING", metaType: "DIM" },
|
|
9
|
+
{ fdId: "p2670dd6b74fc78c3e9c57ad", name: "月份", fdType: "DATE", metaType: "DIM" },
|
|
10
|
+
{ fdId: "lb1c31b4dc86511a27049a98", name: "营收", fdType: "DOUBLE", metaType: "METRIC" },
|
|
11
|
+
{ fdId: "aece10cd6806966be56f52ff", name: "成本", fdType: "DOUBLE", metaType: "METRIC" },
|
|
12
|
+
{ fdId: "g1b16b52a16eb10c5e26d4bb", name: "数量", fdType: "INT", metaType: "METRIC" },
|
|
13
|
+
{ fdId: "eae7cae6fbdcde68acdf5d1f", name: "利润率", fdType: "DOUBLE", metaType: "METRIC" }
|
|
14
|
+
], { displayType: "EXCEL" });
|
|
@@ -4,8 +4,8 @@ var text = createTextCard("Tab 使用说明")
|
|
|
4
4
|
"### Tab 布局示例\n\n" +
|
|
5
5
|
"- `createTab()` 创建容器\n" +
|
|
6
6
|
"- `addPanel(name, callback)` 创建页面上可切换的标签\n" +
|
|
7
|
-
"- panel 内通过 cardIndex
|
|
8
|
-
">
|
|
7
|
+
"- panel 内通过 cardIndex 放置图表/文本等卡片,也可以用 selector 字符串 ID 放置筛选器\n\n" +
|
|
8
|
+
"> 未放入画布布局的筛选器会进入筛选器栏;用 `placeCard(\"selectorId\")` 放入 panel/root/cardGroup 后,同页筛选器栏不再重复展示。"
|
|
9
9
|
);
|
|
10
10
|
|
|
11
11
|
registerTextCard(text.build());
|
|
@@ -15,7 +15,7 @@ var salesTab = createTab("销售分析")
|
|
|
15
15
|
|
|
16
16
|
var page = createPage("Tab Layout 示例")
|
|
17
17
|
.setId("pppppppppppppppppppppppp")
|
|
18
|
-
.setDescription("展示根布局指标卡、tab 容器、panel 内图表/文本卡片,以及 selector
|
|
18
|
+
.setDescription("展示根布局指标卡、tab 容器、panel 内图表/文本卡片,以及 selector 可默认进入筛选器栏或用字符串 ID 放入画布。")
|
|
19
19
|
.setCardMargin(8)
|
|
20
20
|
.addRow([{ card: 0, w: 4 }], 3)
|
|
21
21
|
.addTab(salesTab);
|
|
@@ -129,11 +129,26 @@ f("订单日期", { granularity: Granularity.DAY }) // 按天
|
|
|
129
129
|
- 时间类型:日环比、周同比、月同比、季同比、年同比、年同比(按周)
|
|
130
130
|
- 期末值:上月末、上季度末、上年末
|
|
131
131
|
- 自定义:后移 1 个月
|
|
132
|
-
-
|
|
132
|
+
- 输出值:增长值、增长率、对比值、本期/对比期(内置自定义公式预设)
|
|
133
133
|
- 增长率类型:普通增长率、绝对增长率
|
|
134
134
|
|
|
135
135
|
默认规则:同比、环比、同环比、年同比、月环比等语义未指定输出值时默认生成增长率;未指定模式时默认生成日期筛选模式(`ComparativeMode.FILTER_BASED`),保证页面日期筛选器联动生效。需要普通模式时显式传 `{ mode: ComparativeMode.NORMAL }`;需要增长值或对比值时显式传 `ComparativeOutput.GROWTH_VALUE` / `ComparativeOutput.COMPARE_VALUE`。
|
|
136
136
|
|
|
137
|
+
预聚合周期字段(例如数据集中已经按周产出的 `周开始日期`、按月产出的 `月开始日期`)不能按默认 DAY 筛选窗口计算。使用这类字段做周环比/月环比时,把日期字段声明为 `Granularity.NONE`,builder 会自动生成不带筛选窗口和 `mode` 的同环比:
|
|
138
|
+
|
|
139
|
+
```javascript
|
|
140
|
+
var weekStart = f("周开始日期", { granularity: Granularity.NONE });
|
|
141
|
+
|
|
142
|
+
createCard(ChartType.PIVOT_TABLE, "周报")
|
|
143
|
+
.bindDataset(DS)
|
|
144
|
+
.addRow(weekStart)
|
|
145
|
+
.addMetric(f("GMV", {
|
|
146
|
+
alias: "GMV周环比",
|
|
147
|
+
aggrType: AggrType.SUM,
|
|
148
|
+
advCalc: comparative.weekOverWeek(weekStart)
|
|
149
|
+
}));
|
|
150
|
+
```
|
|
151
|
+
|
|
137
152
|
示例:
|
|
138
153
|
|
|
139
154
|
```javascript
|
|
@@ -159,6 +174,11 @@ createCard(ChartType.PIVOT_TABLE, "销售同环比")
|
|
|
159
174
|
aggrType: AggrType.SUM,
|
|
160
175
|
advCalc: comparative.monthOverMonth(dateField, ComparativeOutput.COMPARE_VALUE)
|
|
161
176
|
}))
|
|
177
|
+
.addMetric(f("销售额", {
|
|
178
|
+
alias: "本期除以去年同期",
|
|
179
|
+
aggrType: AggrType.SUM,
|
|
180
|
+
advCalc: comparative.yearOverYear(dateField, ComparativeOutput.CURRENT_OVER_COMPARE)
|
|
181
|
+
}))
|
|
162
182
|
.addMetric(f("销售额", {
|
|
163
183
|
alias: "上月末增长值",
|
|
164
184
|
aggrType: AggrType.SUM,
|
|
@@ -192,6 +212,7 @@ createCard(ChartType.KPI_CARD, "销售额 KPI")
|
|
|
192
212
|
- `ComparativeOutput.GROWTH_VALUE`:增长值
|
|
193
213
|
- `ComparativeOutput.GROWTH_RATE`:增长率
|
|
194
214
|
- `ComparativeOutput.COMPARE_VALUE`:对比值
|
|
215
|
+
- `ComparativeOutput.CURRENT_OVER_COMPARE`:本期 / 对比期,底层生成 `valueType: "CUSTOM"` 与公式 `[orig]/[shifted]`
|
|
195
216
|
- `GrowthRateType.NORMAL`:普通增长率,默认值
|
|
196
217
|
- `GrowthRateType.ABS`:绝对增长率
|
|
197
218
|
- `ComparativeMode.FILTER_BASED`:日期筛选模式,默认值,用于复现前端「对比」槽位 + 日期筛选的高级计算
|
|
@@ -11,12 +11,18 @@
|
|
|
11
11
|
| `.addColumn(field)` | 添加列维度(按维度分组着色,如按地区/类别分色)。仅 `STACKED_COLUMN`、`GROUPED_COLUMN`、`GROUPED_BAR` 等多指标图表支持 |
|
|
12
12
|
| `.addMetric(field)` | 添加度量(Y 轴,主轴) |
|
|
13
13
|
| `.addMetricAdditional(field)` | 添加副轴度量(仅组合图 `*_WITH_LINE`/`*_WITH_SYMBOL`),默认绑定副 Y 轴(`plotOn: secondary`) |
|
|
14
|
+
| `.addDynamicRow(name, fields, options?)` | 添加动态维度组,候选字段写入 row |
|
|
15
|
+
| `.addDynamicColumn(name, fields, options?)` | 添加动态维度组,候选字段写入 column |
|
|
16
|
+
| `.addDynamicMetric(name, fields, options?)` | 添加动态数值组,候选字段写入 metric |
|
|
17
|
+
| `.addDynamicMetricAdditional(name, fields, options?)` | 添加动态数值组,候选字段写入副轴 |
|
|
14
18
|
| `.addColorBy(field)` | 按指标值渐变着色(接受度量字段,不是维度)|
|
|
15
19
|
| `.addTooltip(field)` / `.addFilter(field)` | 提示/筛选 |
|
|
16
20
|
| `.addSort(field)` / `.addSplit(field)` / `.addSize(field)` | 排序/拆分/大小 |
|
|
17
21
|
| `.addLocation(field)` / `.addTarget(field)` / `.addCompare(field)` | 位置/目标/对比 |
|
|
18
22
|
| `.setSplitSetting({ rows, columns })` | 拆分行列数(默认各 3),需配合 `.addSplit(field)` |
|
|
19
23
|
| `.setColorByColors(preset_or_config)` | colorBy 渐变色。传 `ColorByPreset.RedGreen` 等预设名称,或 `{ startColor, endColor, middleColor?, steps? }` 自定义 hex 颜色 |
|
|
24
|
+
| `.setShapeColorType(type)` | 图形填充方式。默认不调用为纯色;支持 `ShapeColorType.TransparentGradient`,仅用于前端已支持的柱/条类图表 |
|
|
25
|
+
| `.setShowTitle(show)` | 是否显示卡片标题;隐藏标题用 `.setShowTitle(false)` |
|
|
20
26
|
| `.setShowLegend(show, position)` | 图例 |
|
|
21
27
|
| `.setDataLabel(config)` | 数据标签 |
|
|
22
28
|
| `.setAxis(config)` | 轴配置(见下方 Axis Config 详解) |
|
|
@@ -29,6 +35,19 @@
|
|
|
29
35
|
| `.setRawSettings(key, value)` | 原始设置 |
|
|
30
36
|
| `.build()` | 构建(触发验证) |
|
|
31
37
|
|
|
38
|
+
动态字段是显式能力,不会根据同一区域多个字段自动推断。只有调用 `.addDynamicRow()` / `.addDynamicColumn()` / `.addDynamicMetric()` / `.addDynamicMetricAdditional()` 时,才会生成 `zoneData.*[].dzId` 和 `meta.chartMain.dynamicZoneInfo`。
|
|
39
|
+
|
|
40
|
+
动态字段 `options`:
|
|
41
|
+
|
|
42
|
+
| 字段 | 默认值 | 说明 |
|
|
43
|
+
|---|---|---|
|
|
44
|
+
| `defaultValue` | 第一个候选字段 | 推荐传候选数组里的字段对象;字符串只在唯一命中 `name` / `alias` / `fdId` / `id` 时可用 |
|
|
45
|
+
| `multiSelect` | 根据 zone `maxCount` 推断 | `maxCount=1` 时强制单选;维度切换常建议显式写 `false` |
|
|
46
|
+
| `orderType` | `DynamicFieldOrder.PRESET` | `PRESET` 按预置顺序,`CLICK` 按用户点击顺序 |
|
|
47
|
+
| `id` | 自动生成 | 可选,显式指定 `dzId`,用于稳定 diff |
|
|
48
|
+
|
|
49
|
+
`hidden` 和 `selectType` 不开放配置;资源包固定写 `hidden: false`、`selectType: "SEARCHBOX"`。动态字段不写 `stateValue.dzFieldValues`,前端加载卡片时会根据 `dynamicZoneInfo.dzMappings.defaultValue` 初始化默认选中值。
|
|
50
|
+
|
|
32
51
|
### MetricChartBuilder(指标平台指标卡片)
|
|
33
52
|
|
|
34
53
|
用于“用指标平台已有指标创建卡片”,生成后端 `CARD_TYPE.METRIC_CHART`(`cdType=13`)。不要用普通 `createCard()` 伪造,也不要把指标 ID 当作数据集字段。
|
|
@@ -45,8 +64,10 @@
|
|
|
45
64
|
| `.setId(cardId)` | 设置 24 位资源 ID,用于重复导入覆盖 |
|
|
46
65
|
| `.addRow(field)` / `.addColumn(field)` | 添加指标适用维度 |
|
|
47
66
|
| `.addMetric(metric)` | 添加指标平台指标;至少一个 |
|
|
67
|
+
| `.addDynamicRow(name, fields, options?)` / `.addDynamicColumn(name, fields, options?)` | 添加指标平台动态维度组 |
|
|
68
|
+
| `.addDynamicMetric(name, fields, options?)` / `.addDynamicMetricAdditional(name, fields, options?)` | 添加指标平台动态指标组 |
|
|
48
69
|
| `.addFilter(field, filterType, filterValue)` / `.addSort(field)` | 添加筛选/排序 |
|
|
49
|
-
| `.setShowLegend()` / `.setDataLabel()` / `.setAxis()` / `.setTableSetting()` / `.setRawSettings()` | 常用图表设置,和普通 CardBuilder 一致 |
|
|
70
|
+
| `.setShowTitle()` / `.setShowLegend()` / `.setDataLabel()` / `.setAxis()` / `.setTableSetting()` / `.setRawSettings()` | 常用图表设置,和普通 CardBuilder 一致 |
|
|
50
71
|
| `.setProps(obj)` / `.setRawProps(key, value)` | 设置指标卡片 `meta.chartMain.props` |
|
|
51
72
|
| `.setConfig(obj)` / `.setRawConfig(key, value)` | 设置指标卡片 `meta.chartMain.config` |
|
|
52
73
|
| `.setSummary(obj)` | 设置指标卡片 `meta.summary` |
|
|
@@ -66,6 +87,21 @@ var card = createMetricChart(ChartType.PIVOT_TABLE, "销售指标分析")
|
|
|
66
87
|
registerMetricChart(card.build());
|
|
67
88
|
```
|
|
68
89
|
|
|
90
|
+
#### Shape Color Type(图形填充方式)
|
|
91
|
+
|
|
92
|
+
`setShapeColorType()` 控制柱子/条形等图形本身的填充方式,和 `.addColorBy()` / `.setColorByColors()` 的“按度量值渐变着色”不同。默认不调用时保持 BI 默认纯色。
|
|
93
|
+
|
|
94
|
+
```javascript
|
|
95
|
+
var card = createCard(ChartType.BASIC_COLUMN, "区域销售额")
|
|
96
|
+
.setId("card12345678901234567890")
|
|
97
|
+
.bindDataset(DS)
|
|
98
|
+
.addRow(f("区域"))
|
|
99
|
+
.addMetric(f("销售额", { aggrType: AggrType.SUM }))
|
|
100
|
+
.setShapeColorType(ShapeColorType.TransparentGradient);
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
支持的图表:`BASIC_COLUMN`、`BASIC_BAR`、`GROUPED_COLUMN`、`GROUPED_BAR`、`GROUPED_COLUMN_WITH_LINE`、`GROUPED_COLUMN_WITH_SYMBOL`、`BULLET_BAR`。
|
|
104
|
+
|
|
69
105
|
多指标示例:
|
|
70
106
|
|
|
71
107
|
```javascript
|
|
@@ -164,8 +200,8 @@ registerMetricChart(card.build());
|
|
|
164
200
|
|
|
165
201
|
#### Card Linkage(图表卡片点击联动)
|
|
166
202
|
|
|
167
|
-
`CardBuilder.linkTo(target, config)`
|
|
168
|
-
通过 `settings.asFilter` 配置联动关系,通过 `settings.interaction`配置默认交互,不是 selector
|
|
203
|
+
`CardBuilder.linkTo(target, config)` 用于让一个普通图表卡片、固定路径下钻子卡,或自定义图表的 data view(子卡片),在点击维度值后过滤同一页面内的目标图表卡片。
|
|
204
|
+
通过 `settings.asFilter` 配置联动关系,通过 `settings.interaction`配置默认交互,不是 selector 联动。自定义图表作为联动源时还需在 `renderChart` 里回传 `clickFunc`(见 Custom Chart 章节)。
|
|
169
205
|
|
|
170
206
|
```javascript
|
|
171
207
|
// card_00_region_sales.js
|
|
@@ -289,25 +325,46 @@ overview.linkTo("bbbbbbbbbbbbbbbbbbbbbbbb", {
|
|
|
289
325
|
|
|
290
326
|
**布局单位**:
|
|
291
327
|
1. 默认横向使用 12 列栅格;开启精细模式后使用 60 列栅格。
|
|
292
|
-
2. 推荐通过 `.setFineMode(true)` 设置为精细模式,且必须在任何 `addRow()` / `placeCard()` / `addTab()` / `addAreaTitle()` / `addCardGroup()` 等布局方法之前调用。
|
|
328
|
+
2. 推荐通过 `.setFineMode(true)` 设置为精细模式,且必须在任何 `addRow()` / `placeCard()` / `addTab()` / `addAreaTitle()` / `addCardGroup()` / `addSelectorGroup()` 等布局方法之前调用。
|
|
293
329
|
3. `addRow()` 及其快捷方法的 `height` 省略或为 0 时使用默认行高(普通 6,精细 18)。
|
|
294
330
|
4. 区域小标题用 `createAreaTitle(...).setId(...).build()` 定义,并通过 `page.addAreaTitle(title)` 放在 Page 根布局;不要放进 tab panel。
|
|
295
331
|
5. 卡片组用 `createCardGroup(...).setId(...)` 定义,并通过 `page.addCardGroup(group)` 放在 Page 根布局。
|
|
332
|
+
6. 筛选器组用 `createSelectorGroup(...).setId(...)` 定义;画布组通过 `page.addSelectorGroup(group)` 放在 Page 根布局,筛选栏组通过 `page.addFilterSelectorGroup(group)` 加入筛选栏,未分组 selector 可通过 `page.addFilterSelector(selectorId)` 显式控制顺序;组内只能放 selector。checkout 后修改已有快捷筛选区时,优先用 `setFilterLayout()` / `clearFilterLayout()` / `addFilterLayoutItem()` / `insertFilterSelector()` / `removeFilterSelector()` / `moveFilterSelector()` 表达增量操作;筛选器或筛选器组需要在快捷筛选区和画布之间移动时,优先用动作级 `moveFilterSelectorToCanvas()` / `moveCanvasSelectorToFilter()` / `moveSelectorGroupToCanvas()` / `moveCanvasSelectorGroupToFilter()`,不要手改 base JSON。
|
|
333
|
+
7. checkout 生成的根布局组件会使用 `page.placeTab()` / `placeAreaTitle()` / `placeCardGroup()` / `placeSelectorGroup()` 保留线上 x/y/w/h;新建工程通常继续用 `addTab()` / `addAreaTitle()` / `addCardGroup()` / `addSelectorGroup()` 自动满宽布局。
|
|
334
|
+
8. 下文布局 API 中的 `cardRef` 表示:推荐使用已注册卡片或 selector 的字符串 ID;数字 index 仍可用于非 selector 卡片,按可布局资源注册顺序计数。`registerSelector()` 不参与数字 index 计数;被布局引用的 selector 不再进入同页筛选器栏。
|
|
296
335
|
|
|
297
336
|
| 方法 | 说明 |
|
|
298
337
|
|------|------|
|
|
299
338
|
| `createPage(name)` | 创建 Page |
|
|
300
339
|
| `.setId(pgId)` | 设置 Page ID |
|
|
301
340
|
| `.setParentDir(dirId)` | 设置页面所在目录 ID(不设置则在根目录),目录 ID 可通过 `guancli page tree` 获取 |
|
|
302
|
-
| `.addRow(specs, height?)` | **推荐**:灵活行布局,specs = `[{ card:
|
|
303
|
-
| `.addFullWidthCard(
|
|
304
|
-
| `.addHalfWidthCards(
|
|
305
|
-
| `.addThirdWidthCards(
|
|
306
|
-
| `.addQuarterWidthCards(
|
|
307
|
-
| `.placeCard(
|
|
341
|
+
| `.addRow(specs, height?)` | **推荐**:灵活行布局,specs = `[{ card: cardRef, w: colSpan }, ...]`;不传 w 时自动等分当前栅格 |
|
|
342
|
+
| `.addFullWidthCard(cardRef, height?)` | 全宽行,等价于 `addRow([{ card }], height)` |
|
|
343
|
+
| `.addHalfWidthCards(a, b, height?)` | 左右各半 |
|
|
344
|
+
| `.addThirdWidthCards(a, b, c, height?)` | 三等分 |
|
|
345
|
+
| `.addQuarterWidthCards(a, b, c, d, height?)` | 四等分 |
|
|
346
|
+
| `.placeCard(cardRef, x, y, w, h)` | 精确放置 Card,`w/h` 必须大于 0, `x/y/w/h` 必须显式填写 |
|
|
308
347
|
| `.addTab(tab, height?)` | 添加一个满宽 tab 容器;不传 height 时按第一个 panel 内容自动推导 |
|
|
309
348
|
| `.addAreaTitle(areaTitle, height?)` | 添加一个满宽区域小标题|
|
|
310
349
|
| `.addCardGroup(group, height?)` | 添加一个满宽卡片组;不传 height 时按标题和组内布局自动推导 |
|
|
350
|
+
| `.addSelectorGroup(group, height?)` | 添加一个满宽画布筛选器组;不传 height 时按展示模式、标题和组内布局自动推导 |
|
|
351
|
+
| `.placeTab(tab, x, y, w, h)` | checkout/精确布局用:注册 tab 并按显式坐标放入 Page 根布局 |
|
|
352
|
+
| `.placeAreaTitle(areaTitle, x, y, w, h)` | checkout/精确布局用:注册区域小标题并按显式坐标放入 Page 根布局 |
|
|
353
|
+
| `.placeCardGroup(group, x, y, w, h)` | checkout/精确布局用:注册卡片组并按显式坐标放入 Page 根布局 |
|
|
354
|
+
| `.placeSelectorGroup(group, x, y, w, h)` | checkout/精确布局用:注册画布筛选器组并按显式坐标放入 Page 根布局 |
|
|
355
|
+
| `.removeLayoutItem(cardRef)` | 从当前 Page 根布局移除已放置的 card/selector/layout component;主要给动作级移动 API 使用 |
|
|
356
|
+
| `.addFilterSelectorGroup(group)` | 添加一个筛选栏筛选器组 |
|
|
357
|
+
| `.addFilterSelector(selectorId)` | 显式添加一个未分组的筛选栏 selector,并控制其与筛选器组的顺序 |
|
|
358
|
+
| `.setFilterLayout(items)` | 整体设置快捷筛选区的 selector / filter selectorGroup ID 列表;checkout 场景会覆盖 base `filterLayout` |
|
|
359
|
+
| `.clearFilterLayout()` | 清空快捷筛选区;常用于把已有快捷筛选器改成画布内普通筛选器卡片 |
|
|
360
|
+
| `.addFilterLayoutItem(items)` | 向快捷筛选区追加 selector / filter selectorGroup ID,已存在则跳过 |
|
|
361
|
+
| `.insertFilterLayoutItem(index, items)` / `.insertFilterSelector(index, selectorId)` | 在快捷筛选区指定位置插入 |
|
|
362
|
+
| `.removeFilterLayoutItem(id)` / `.removeFilterSelector(selectorId)` | 从快捷筛选区移除已有 selector / filter selectorGroup ID |
|
|
363
|
+
| `.moveFilterLayoutItem(id, index)` / `.moveFilterSelector(selectorId, index)` | 调整快捷筛选区已有项顺序 |
|
|
364
|
+
| `.moveFilterSelectorToCanvas(selectorId, x, y, w, h)` | 动作级:从快捷筛选区移除 selector,并按坐标放到 Page 画布,联动配置保留在 selector 卡片本身 |
|
|
365
|
+
| `.moveCanvasSelectorToFilter(selectorId, index?)` | 动作级:从 Page 根布局移除 selector,并加入快捷筛选区;传 `index` 时插入指定位置,否则追加 |
|
|
366
|
+
| `.moveSelectorGroupToCanvas(group, x, y, w, h)` / `.moveFilterSelectorGroupToCanvas(group, x, y, w, h)` | 动作级:把筛选栏 SelGroup 转换成画布 SelGroup,并从快捷筛选区移除 |
|
|
367
|
+
| `.moveCanvasSelectorGroupToFilter(group, index?)` | 动作级:把画布 SelGroup 转换成筛选栏 SelGroup,并从 Page 根布局移除;组内布局必须引用 selector ID 字符串 |
|
|
311
368
|
| `.setBackgroundColor(color)` | 页面背景色 |
|
|
312
369
|
| `.setCardMargin(margin)` | 卡片间距 |
|
|
313
370
|
| `.setFineMode(enabled)` | 开启/关闭精细模式 |
|
|
@@ -323,6 +380,7 @@ overview.linkTo("bbbbbbbbbbbbbbbbbbbbbbbb", {
|
|
|
323
380
|
|------|------|
|
|
324
381
|
| `createAreaTitle(name)` | 创建区域小标题,`name` 即为标题的内容,会被写入该组件的 style 中,必须要传 name |
|
|
325
382
|
| `.setId(areaTitleId)` | **必填**。设置区域小标题 ID,必须以 `areaTitle_` 开头 |
|
|
383
|
+
| `.setRawStyle(style)` | checkout 保留线上 style 用;新建工程优先用下列语义化方法 |
|
|
326
384
|
| `.setShowTitle(boolean)` | 是否显示标题 |
|
|
327
385
|
| `.setFontSize(number)` | 字号 |
|
|
328
386
|
| `.setColor(color)` | 字体颜色 |
|
|
@@ -357,10 +415,13 @@ registerPage(page.build());
|
|
|
357
415
|
|------|------|
|
|
358
416
|
| `createCardGroup(name)` | 创建卡片组,`name` 写入分组标题 |
|
|
359
417
|
| `.setId(cardGroupId)` | **必填**。设置卡片组 ID,必须以 `cardGroup_` 开头 |
|
|
418
|
+
| `.setRawStyle(style)` | checkout 保留线上 style 用;新建工程优先用 `.setShowTitle()` 等语义化方法 |
|
|
360
419
|
| `.setShowTitle(boolean)` | 是否显示标题,默认 `true` |
|
|
361
420
|
| `.addRow(specs, height?)` | 在组内按行放置卡片,写法同 `PageBuilder.addRow()` |
|
|
362
|
-
| `.addFullWidthCard(
|
|
363
|
-
| `.placeCard(
|
|
421
|
+
| `.addFullWidthCard(cardRef, height?)` | 在组内放一张满宽卡片 |
|
|
422
|
+
| `.placeCard(cardRef, x, y, w, h)` | 在组内精确放置卡片 |
|
|
423
|
+
|
|
424
|
+
卡片组内布局方法同 `PageBuilder`,使用 `cardRef`。
|
|
364
425
|
|
|
365
426
|
```javascript
|
|
366
427
|
var salesGroup = createCardGroup("销售概览")
|
|
@@ -375,6 +436,57 @@ var page = createPage("销售仪表板")
|
|
|
375
436
|
registerPage(page.build());
|
|
376
437
|
```
|
|
377
438
|
|
|
439
|
+
### SelectorGroupBuilder
|
|
440
|
+
|
|
441
|
+
`SelGroup` 是原生筛选器组,不是 Card,不绑定数据集,也不会生成独立 page-card relation。ID 必须以 `selGroup_` 开头,使用 `guanvis gen-layout-id selGroup` 生成。画布 SelGroup 只能放入 Page 根布局;筛选栏 SelGroup 只能放入 `filterLayout`;组内只能包含已注册 selector。
|
|
442
|
+
|
|
443
|
+
默认值:`displayMode = "tiled"`、`showTitle = false`、`titleStyle.fontSize = 14`、`titleStyle.bold = true`。筛选栏组名始终来自 `name`,不受 `showTitle` 控制。
|
|
444
|
+
|
|
445
|
+
| 方法 | 说明 |
|
|
446
|
+
|------|------|
|
|
447
|
+
| `createSelectorGroup(name)` | 创建筛选器组,`name` 必填 |
|
|
448
|
+
| `.setId(selGroupId)` | **必填**。设置筛选器组 ID,必须以 `selGroup_` 开头 |
|
|
449
|
+
| `.setRawStyle(style)` | checkout 保留线上 style 用;新建工程优先用 `.setDisplayMode()` / `.setShowTitle()` / `.setFpWidth()` |
|
|
450
|
+
| `.setDisplayMode(mode)` | 展示模式:`SelectorGroupDisplayMode.TILED`(默认)或 `SelectorGroupDisplayMode.DROPDOWN` |
|
|
451
|
+
| `.setShowTitle(boolean)` | 是否显示画布组标题;默认 `false` |
|
|
452
|
+
| `.setFpWidth(width)` | 筛选栏非栅格模式宽度,仅筛选栏组有效 |
|
|
453
|
+
| `.setFpGrid(span)` | 筛选栏栅格模式宽度,仅筛选栏组有效 |
|
|
454
|
+
| `.addSelector(selectorId)` / `.addSelectors(selectorIds)` | 添加筛选栏组内 selector;使用后只能传给 `page.addFilterSelectorGroup()` |
|
|
455
|
+
| `.addRow(specs, height?)` | 添加画布组内 selector 布局,写法同 `PageBuilder.addRow()`;height 省略或为 0 时 selector 高度默认普通 1、精细 3;使用后只能传给 `page.addSelectorGroup()` |
|
|
456
|
+
| `.addFullWidthCard(cardRef, height?)` | 在画布组内放一个满宽 selector |
|
|
457
|
+
| `.placeCard(cardRef, x, y, w, h)` | 在画布组内精确放置 selector |
|
|
458
|
+
|
|
459
|
+
画布下拉筛选器组:
|
|
460
|
+
|
|
461
|
+
```javascript
|
|
462
|
+
var advanced = createSelectorGroup("高级筛选")
|
|
463
|
+
.setId("selGroup_AbCdEf")
|
|
464
|
+
.setDisplayMode(SelectorGroupDisplayMode.DROPDOWN)
|
|
465
|
+
.setShowTitle(true)
|
|
466
|
+
.addRow([
|
|
467
|
+
{ card: "ssssssssssssssssssssssss", w: 6 },
|
|
468
|
+
{ card: "tttttttttttttttttttttttt", w: 6 }
|
|
469
|
+
]);
|
|
470
|
+
|
|
471
|
+
var page = createPage("销售仪表板")
|
|
472
|
+
.setId("p184352b7a76776db5f534df")
|
|
473
|
+
.addSelectorGroup(advanced);
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
筛选栏筛选器组与未分组筛选器混排:
|
|
477
|
+
|
|
478
|
+
```javascript
|
|
479
|
+
var globalFilters = createSelectorGroup("全局筛选")
|
|
480
|
+
.setId("selGroup_GhIjKl")
|
|
481
|
+
.addSelector("ssssssssssssssssssssssss")
|
|
482
|
+
.addSelector("tttttttttttttttttttttttt");
|
|
483
|
+
|
|
484
|
+
var page = createPage("销售仪表板")
|
|
485
|
+
.setId("p184352b7a76776db5f534df")
|
|
486
|
+
.addFilterSelectorGroup(globalFilters)
|
|
487
|
+
.addFilterSelector("uuuuuuuuuuuuuuuuuuuuuuuu");
|
|
488
|
+
```
|
|
489
|
+
|
|
378
490
|
#### 页面密度尺寸建议
|
|
379
491
|
|
|
380
492
|
以下尺寸建议以非精细模式的 12 列布局单位为基准,用于生成页面时选择页面卡片间距和常见卡片高度。精细模式目前只定义横向 60 列栅格与显式 `x/y/w/h` 放置规则,暂不提供独立的密度尺寸换算规则。
|
|
@@ -401,14 +513,17 @@ tab 用于把页面中的卡片分到多个 panel。适合同一主题下多组
|
|
|
401
513
|
|------|------|
|
|
402
514
|
| `createTab(name)` | 创建 tab 容器;`name` 用于脚本可读性,页面上显示的是各 panel 的 name |
|
|
403
515
|
| `.setId(tabId)` | **必填**。设置 tab ID,必须以 `tab_` 开头且同一页面内唯一。建议用 `guanvis gen-layout-id tab` 生成 |
|
|
516
|
+
| `.setRawStyle(style)` | checkout 保留线上 tab style 用;新建工程优先用下列语义化方法 |
|
|
517
|
+
| `.setRawPanelStyle(panelStyle)` | checkout 保留线上 panelStyle 用 |
|
|
518
|
+
| `.setRawLayoutItemMap(layoutItemMap)` | checkout 保留线上 tab 内 layoutItemMap 用 |
|
|
404
519
|
| `.addPanel(name, callback)` | 添加 panel;callback 接收 `panel` 配置对象,必须在其中放入至少一张卡片 |
|
|
405
520
|
| `.setLabelStyle(style)` | 设置标签样式:`TabLabelStyle.UNDERLINE`(默认)、`CARD`、`CAPSULE`、`TRAPEZOID` |
|
|
406
521
|
| `.setAlignment(alignment)` | 设置标签对齐:`TabAlignment.LEFT`(默认)、`CENTER`、`RIGHT` |
|
|
407
522
|
| `.setTabSize(size)` | 设置标签宽度:`TabSizeType.MAX_CONTENT`(默认)或 `FLEX` |
|
|
408
523
|
| `panel.setId(panelId)` | **必填**。设置 panel ID,必须以 `panel_` 开头且同一页面内唯一。建议用 `guanvis gen-layout-id panel` 生成 |
|
|
409
524
|
| `panel.addRow(specs, height?)` | 在 panel 内按行放置卡片,写法同 `PageBuilder.addRow()` |
|
|
410
|
-
| `panel.addFullWidthCard(
|
|
411
|
-
| `panel.placeCard(
|
|
525
|
+
| `panel.addFullWidthCard(cardRef, height?)` | 在 panel 内放一张满宽卡片 |
|
|
526
|
+
| `panel.placeCard(cardRef, x, y, w, h)` | 在 panel 内精确放置卡片 |
|
|
412
527
|
|
|
413
528
|
**使用示例**:
|
|
414
529
|
|
|
@@ -438,13 +553,17 @@ registerPage(page.build());
|
|
|
438
553
|
注意:
|
|
439
554
|
|
|
440
555
|
- tab 必须有 panel,panel 必须有卡片;不要创建空 tab 或空 panel。
|
|
441
|
-
- panel
|
|
556
|
+
- panel 内布局方法同 `PageBuilder`,使用 `cardRef`。
|
|
442
557
|
- panel 布局跟随页面精细模式:`page.setFineMode(true)` 后,panel 也使用 60 列栅格和精细模式默认行高。
|
|
443
558
|
- 不需要手工设置 tab 高度;只有明确要固定高度时才给 `page.addTab(tab, height)` 传第二个参数。
|
|
444
559
|
|
|
445
560
|
### SelectorBuilder(筛选器)
|
|
446
561
|
|
|
447
|
-
筛选器是特殊的卡片(`cdType=6
|
|
562
|
+
筛选器是特殊的卡片(`cdType=6`),可联动影响其他图表卡片。默认情况下,注册后未被页面布局引用的 selector 会进入页面筛选器栏;如需把筛选器作为画布内容展示,在 `page.js` 中使用 selector 字符串 ID 作为 `cardRef`。
|
|
563
|
+
|
|
564
|
+
**布局归属**:
|
|
565
|
+
- 全局筛选器可进入页面筛选器栏,并按需使用 `.linkToAll()`。
|
|
566
|
+
- 凡是作为画布内容或隶属于某个分区、Tab、CardGroup 的筛选器,必须跟随所属布局放置,不进入筛选栏。局部筛选器使用 `.linkTo(...)` 明确联动所属分区内图表,不默认 `.linkToAll()`。
|
|
448
567
|
|
|
449
568
|
| 方法 | 说明 |
|
|
450
569
|
|------|------|
|
|
@@ -458,7 +577,7 @@ registerPage(page.build());
|
|
|
458
577
|
| `.setGranularityOptions(options, defaultGranularity?)` | 设置 `CALENDAR` 可选日期粒度列表和默认粒度,例如 `[Granularity.MONTH, Granularity.QUARTER]`。未显式设置时会从目标卡片日期字段粒度自动推断 |
|
|
459
578
|
| `.setTimeMacroOptions(options, defaultMacroName?)` | 设置快捷日期选项(自动设置 `selectorType` 为 `TIME_MACRO`)。`options`: `[{ name, expr }]`,`expr` 使用内置宏名(见示例)。`defaultMacroName` 默认选中的宏名,传 `null` 则不选(页面打开时无默认值),不传则取第一项。不需要 `bindField` 和 `bindDataset` |
|
|
460
579
|
| `.setMultiSelect(bool)` | 是否多选(默认 false) |
|
|
461
|
-
| `.setDefaultType(type)` | 默认值类型:`SelectorDefaultType.FIRST_PICK
|
|
580
|
+
| `.setDefaultType(type)` | 默认值类型:`SelectorDefaultType.FIRST_PICK`、`FIXED_VALUE` 或 `ALL`。未显式设置时按 `ALL`/空值生成;作为级联目标且默认是 `ALL`/空值时会自动改为 `FIRST_PICK` |
|
|
462
581
|
| `.setDefaultAll()` | 设置默认"全部"(不筛选),等价于 `setDefaultType(SelectorDefaultType.ALL)` |
|
|
463
582
|
| `.setDefaultValue(values, displayValues?)` | 设置固定默认值,自动切换为 FIXED_VALUE 类型 |
|
|
464
583
|
| `.setDefaultDateRange(start, end, displayValues?)` | 设置 `CALENDAR` 日期区间默认值,自动切换为 FIXED_VALUE;比手写数组更不容易漏填区间端点 |
|
|
@@ -467,6 +586,7 @@ registerPage(page.build());
|
|
|
467
586
|
| `.setShowSelectAll(bool)` | 是否显示"全选"(默认 true) |
|
|
468
587
|
| `.setCanClear(bool)` | 是否可清空(默认 true) |
|
|
469
588
|
| `.linkTo(cardIndex, targetFieldName?)` | 联动指定卡片(cardIndex 为过滤后的可联动目标序列:普通图表和 MetricChart 按注册/布局顺序,杜邦子图追加在末尾),可指定目标字段名(默认同名匹配) |
|
|
589
|
+
| `.linkToSelector(selectorId, targetFieldName?)` | 联动指定筛选器(用于省→市→区等级联)。`selectorId` 为目标筛选器 ID;`targetFieldName` 默认按源字段名匹配目标筛选器数据集字段。目标筛选器为 `ALL`/空默认值时会自动启用 `FIRST_PICK + firstPickLink`,固定默认值会保留 |
|
|
470
590
|
| `.linkToAll()` | 自动联动所有普通图表卡片、MetricChart 和杜邦子卡片(按同名字段匹配) |
|
|
471
591
|
| `.build()` | 构建(触发验证) |
|
|
472
592
|
|
|
@@ -535,13 +655,35 @@ registerSelector(sel);
|
|
|
535
655
|
// QUARTER_TO_DAY, QUARTER_TO_YESTERDAY, YEAR_TO_LAST_MONTH, YEAR_TO_LAST_QUARTER
|
|
536
656
|
```
|
|
537
657
|
|
|
658
|
+
```javascript
|
|
659
|
+
// selector_04_cascade.js — 筛选器级联(省 -> 市)
|
|
660
|
+
var city = createSelector("市")
|
|
661
|
+
.setId("bbbbbbbbbbbbbbbbbbbbbbbb")
|
|
662
|
+
.bindField(f("市"))
|
|
663
|
+
.build();
|
|
664
|
+
registerSelector(city);
|
|
665
|
+
|
|
666
|
+
var province = createSelector("省")
|
|
667
|
+
.setId("aaaaaaaaaaaaaaaaaaaaaaaa")
|
|
668
|
+
.bindField(f("省"))
|
|
669
|
+
.linkToSelector("bbbbbbbbbbbbbbbbbbbbbbbb") // 默认用“省”过滤“市”筛选器的数据集
|
|
670
|
+
.linkToAll()
|
|
671
|
+
.build();
|
|
672
|
+
registerSelector(province);
|
|
673
|
+
// 若目标筛选器“市”是 ALL/空默认值(包括显式 setDefaultAll()),
|
|
674
|
+
// 会自动启用 FIRST_PICK + firstPickLink,省变化后自动重选第一项并继续向下游联动。
|
|
675
|
+
// 若目标筛选器已显式 setDefaultValue([...]) 固定默认值,则保持用户设置。
|
|
676
|
+
// 如果目标筛选器数据集中的上游字段不是同名字段,可传第二个参数:
|
|
677
|
+
// .linkToSelector("bbbbbbbbbbbbbbbbbbbbbbbb", "所属省份")
|
|
678
|
+
```
|
|
679
|
+
|
|
538
680
|
**筛选器类型选择指南**:
|
|
539
681
|
- **离散值**(区域、类别、客户名等文本字段)→ `DS_ELEMENTS`(默认),配合 `setDisplayType` 选择展示样式
|
|
540
682
|
- **连续数值范围**(利润率、金额区间等)→ `SelectorType.DS_INTERVAL`,默认区间输入(起始值-结束值)
|
|
541
683
|
- **日期选择**(精确日期范围)→ `SelectorType.CALENDAR`,需要 `bindField` 绑定日期字段。默认会从联动目标卡片推断日期粒度;如需固定月/季度等粒度,可用 `.setGranularity(Granularity.MONTH)` 或 `.setGranularityOptions([...], default)`
|
|
542
684
|
- **快捷日期区间**(本月/上月/近7天等预设区间)→ `.setTimeMacroOptions(options, default)`,不需要 `bindField`,自动匹配目标卡片日期字段联动。`default` 传 `null` 表示无默认值
|
|
543
685
|
|
|
544
|
-
**联动机制**:筛选器通过 `settings.asFilter` 配置联动关系。`linkTo(cardIndex)` 会自动构建 `columnMappings`,将筛选器字段映射到目标卡片的同名字段;cardIndex 只统计普通图表、MetricChart 和杜邦子卡片,文本/图片等不可联动资源不占序号。`linkToAll()` 会自动匹配所有普通图表卡片、MetricChart
|
|
686
|
+
**联动机制**:筛选器通过 `settings.asFilter` 配置联动关系。`linkTo(cardIndex)` 会自动构建 `columnMappings`,将筛选器字段映射到目标卡片的同名字段;cardIndex 只统计普通图表、MetricChart 和杜邦子卡片,文本/图片等不可联动资源不占序号。`linkToSelector(selectorId, targetFieldName?)` 用于筛选器联动筛选器,目标必须是已注册的 DS_ELEMENTS/TREE 筛选器,构建时会检查 selector 级联成环;目标为 ALL/空默认值时会自动改为 `FIRST_PICK + firstPickLink`,目标已有固定默认值时保留用户设置。`linkToAll()` 会自动匹配所有普通图表卡片、MetricChart 和杜邦子卡片中的同名字段,不自动包含筛选器。若同一个筛选器同时写了 `linkTo(index, "自定义字段")` 和 `linkToAll()`,显式 `linkTo` 的目标字段映射优先。
|
|
545
687
|
|
|
546
688
|
**文件命名**:筛选器脚本建议命名为 `selector_NN_xxx.js`,会在 `card_*.js` 之后、`page.js` 之前执行。
|
|
547
689
|
|
|
@@ -759,6 +901,8 @@ registerImageCard(img2.build());
|
|
|
759
901
|
|
|
760
902
|
**数据流**:BI 前端查询子卡片(data view)的数据 → 将结果按列组织为 `data` → 传给自定义图表的 `renderChart(data, clickFunc, config)` 函数(SDK)或直接可用 `data` 变量(ECHARTS_LITE)。
|
|
761
903
|
|
|
904
|
+
**点击联动(custom chart 作为联动源)**:在 data view(子卡片 `CardBuilder`)上调用 `.linkTo(target, { fields: [{ source, target }] })`,即可让自定义图表成为同页联动源——图表内部点击某维度时,按映射过滤目标卡片。`target` 仍按布局 index 或 cardId 解析(不能指向自身所在的自定义图表)。校验、字段匹配、同页与联动环检查与普通图表卡片完全一致,结果写为 data view 的 `settings.asFilter` + `interaction=LINK`。SDK 子类型必须在 `renderChart` 里用第二个入参 `clickFunc` 回传点击:`clickFunc({ clickedItems: [{ idx: [viewIndex, columnIndex], colName: '列名', value: ['选中值'] }] })`;`idx[1]` 指向 data view 行字段的列序号。ECHARTS_LITE 也用同样的 `clickFunc`。
|
|
905
|
+
|
|
762
906
|
`data` 格式(二维数组,外层每个元素对应一个数据视图,内层每个元素对应一个字段列):
|
|
763
907
|
```javascript
|
|
764
908
|
// data[viewIndex][columnIndex] = { name: "字段名", data: [...值], numberFormat: ... }
|
|
@@ -1048,12 +1192,13 @@ option = {
|
|
|
1048
1192
|
| `FieldType` | `STRING`, `INT`, `LONG`, `DOUBLE`, `FLOAT`, `DATE`, `BOOL`, `DECIMAL` | 字段数据类型 |
|
|
1049
1193
|
| `SortOrder` | `ASC`, `DESC` | 排序方向 |
|
|
1050
1194
|
| `Granularity` | `NONE`, `YEAR`, `QUARTER`, `MONTH`, `WEEK`, `DAYOFWEEK`, `DAY`, `HOUR`, `MINUTE`, `SECOND` | 日期粒度 |
|
|
1195
|
+
| `DynamicFieldOrder` | `PRESET`, `CLICK` | 动态字段默认顺序;`PRESET` 按候选顺序,`CLICK` 按用户选择顺序 |
|
|
1051
1196
|
| `FilterType` | `IN`, `NOT_IN`, `GT`, `GE`, `LT`, `LE`, `EQ`, `NE`, `BT`(区间), `CONTAINS`, `NOT_CONTAINS`, `STARTSWITH`, `ENDSWITH`, `IS_NULL`, `NOT_NULL` | 筛选条件类型 |
|
|
1052
1197
|
| `FilterLevel` | `DETAIL`(明细), `AGGREGATION`(聚合), `RESULT`(结果) | 筛选级别 |
|
|
1053
1198
|
| `NumberFormat` | `.number()`, `.currency()`, `.percentage()`, `.auto()`, `.custom()` | 数值格式化工厂 |
|
|
1054
1199
|
| `SelectorType` | `DS_ELEMENTS`(默认), `DS_INTERVAL`, `CALENDAR`, `TIME_MACRO` | 筛选器类型 |
|
|
1055
1200
|
| `SelectorDisplay` | `SEARCH_LIST`(单选下拉), `SEARCH_BOX`(多选下拉), `CHECKBOX`(复选框), `RADIO`(单选框), `BUTTON_GROUP`(按钮组) | 筛选器展示类型,不设置时根据 multiSelect 自动推断 |
|
|
1056
|
-
| `SelectorDefaultType` | `FIRST_PICK
|
|
1201
|
+
| `SelectorDefaultType` | `FIRST_PICK`, `FIXED_VALUE`, `ALL`(默认,全部/不筛选) | 筛选器默认值类型 |
|
|
1057
1202
|
| `CardType` | `CHART`(0), `TEXT`(1), `IFRAME`(2), `PICTURE`(4), `SELECTOR`(6), `LAYOUT`(9) | 卡片类型(内部使用,通常不需要直接引用) |
|
|
1058
1203
|
| `ImageSourceType` | `OUTSIDE_LINK`(1), `LOCAL_IMAGE`(2) | 图片来源类型 |
|
|
1059
1204
|
| `ImageRenderType` | `RATIO`(1,原比例), `STRETCH`(2,拉伸填满), `FIT_TO_CONTENT`(3,自适应内容) | 图片渲染模式 |
|