From d6312fcd16eb2feabeebb32fca8071c7d3f6b089 Mon Sep 17 00:00:00 2001 From: "douboer@gmail.com" Date: Fri, 23 Jan 2026 23:20:39 +0800 Subject: [PATCH] update at 2026-01-23 23:20:39 --- .codex/.gitignore | 1 + public/demo.json | 18 +--- public/demo.json.conf | 37 ++------ public/demo2.json | 31 ++---- public/demo3.json | 160 +++++++++++++++++++++++++++++++ public/luopan-configs.json | 21 ++++ public/rumen.json | 162 +++++++++++++++++++++++++++++++ public/themes.json | 174 ++++++++++++++++++++++++++++++++++ refactor-plan.md | 128 ++++++++++++++++++++++--- src/Luopan.vue | 100 +++++++++++++++++-- src/colorResolver.ts | 22 +++-- src/composables/useLuopan.ts | 103 ++++++++++++++++++-- src/configParser.ts | 13 ++- src/index.ts | 3 + src/multiTextParser.ts | 16 +++- src/sectorBuilder.ts | 34 +++++-- src/types.ts | 23 ++++- src/utils.ts | 26 ++--- tests/colorResolver.test.ts | 10 ++ tests/configParser.test.ts | 5 +- tests/multiTextParser.test.ts | 10 ++ tests/sectorBuilder.test.ts | 19 ++++ tests/utils.test.ts | 2 +- todolist.md | 7 +- 24 files changed, 982 insertions(+), 143 deletions(-) create mode 100644 .codex/.gitignore create mode 100644 public/demo3.json create mode 100644 public/luopan-configs.json create mode 100644 public/rumen.json create mode 100644 public/themes.json diff --git a/.codex/.gitignore b/.codex/.gitignore new file mode 100644 index 0000000..3fec32c --- /dev/null +++ b/.codex/.gitignore @@ -0,0 +1 @@ +tmp/ diff --git a/public/demo.json b/public/demo.json index 9c6828c..73b9c07 100644 --- a/public/demo.json +++ b/public/demo.json @@ -6,23 +6,7 @@ "strokeOpacity": 1, "strokeColor": "黑", "insetDistance": 1, - "theme": { - "name": "五行配色主题", - "colorPalettes": { - "黑": "#000000", - "灰": "#757575", - "白": "#ffffff", - "木": "#43A047", - "火": "#E53935", - "土": "#8D6E63", - "金": "#D4AF37", - "水": "#0288D1", - "热": "#FF8F00", - "冷": "#1976D2", - "强": "#D32F2F", - "软": "#FFE0B2" - } - }, + "themeRef": "五行强", "layers": [ { "type": "centerIcon", diff --git a/public/demo.json.conf b/public/demo.json.conf index 9d43bec..fbcc73f 100644 --- a/public/demo.json.conf +++ b/public/demo.json.conf @@ -26,33 +26,9 @@ -- ======================================== -- 主题配置 -- ======================================== - "theme": { - "name": "五行配色主题", - - -- 文字颜色自动计算:根据背景色明暗度自动选择黑/白文字,确保高对比度 - -- "textOnLight": "#1a1a1a", 已删除,由系统自动计算 - -- "textOnDark": "#ffffff", 已删除,由系统自动计算 - - -- ======================================== - -- 命名配色方案 (Named Color Palettes) - -- ======================================== - -- 定义可复用的命名颜色,在 layers 中通过名称引用 - -- 包含10种配色:黑、灰、白、五行(木火土金水)、热、冷、强、软 - "colorPalettes": { - "黑": "#000000", -- 纯黑 - "灰": "#757575", -- 中灰 - "白": "#ffffff", -- 纯白 - "木": "#43A047", -- 生机绿(五行:木) - "火": "#E53935", -- 烈焰红(五行:火) - "土": "#8D6E63", -- 大地棕(五行:土) - "金": "#78909C", -- 金属灰(五行:金) - "水": "#0288D1", -- 水蓝(五行:水) - "热": "#FF8F00", -- 暖橙(暖色调) - "冷": "#1976D2", -- 冷蓝(冷色调) - "强": "#D32F2F", -- 强烈红(高饱和度) - "\u8f6f": "#FFE0B2" -- 柔和杏(低饱和度) - }, - }, + -- 主题统一放在 public/themes.json 中管理 + -- 通过 themeRef 引用主题名称;不填则使用 themes.json.default + "themeRef": "五行弱", -- ======================================== -- 层配置 (Layers Configuration) @@ -129,7 +105,7 @@ "startAngle": 0, -- 第一个扇区的起始角度(度,0度为正北方向,顺时针) "colorRef": "土", -- 着色使用的颜色引用 "innerFill": 1, -- 着色区域的内缩设置 - -- "start": 1, -- 从第1个扇区开始着色(已废弃,统一从第1个扇区开始) + -- "patternOffset": 2, -- 第一个着色单元偏移1个扇区(可选) "num": 3, -- 连续着色3个扇区 "interval": 1, -- 着色后间隔1个扇区 "sectors": [ @@ -265,17 +241,18 @@ -- 示例:{ "content": "木", "colorRef": "木" } -- -- 优先级2:层级规律填色配置 --- 通过 colorRef + start + num + interval 实现规律着色 +-- 通过 colorRef + patternOffset + num + interval 实现规律着色 -- 未着色的扇区使用全局 background 颜色 -- -- ======================================== -- 规律填色算法说明 -- ======================================== -- startAngle: 第一个扇区的起始角度(度,0度为正北方向,顺时针增加) +-- patternOffset: 规律填色起始偏移(扇区序号,从1开始,默认1,未指定时与startAngle对齐) -- num: 连续着色扇区数量 -- interval: 着色后间隔的扇区数量 -- --- 算法:从第1个扇区开始,循环执行 "着色num个" → "跳过interval个" +-- 算法:从第 patternOffset 个扇区开始,循环执行 "着色num个" → "跳过interval个" -- 特殊情况:interval=0 表示无间隔,全部着色 -- -- 示例:divisions=12, startAngle=0, num=3, interval=1 diff --git a/public/demo2.json b/public/demo2.json index 484e9ad..5f00280 100644 --- a/public/demo2.json +++ b/public/demo2.json @@ -1,25 +1,13 @@ { "name": "demo2", - "description": "luopan demo config with named color palettes", + "description": "luopan demo2 config with named color palettes", "background": "#000000", + "strokeWidth": 1, + "strokeOpacity": 1, + "strokeColor": "白", + "insetDistance": 1, "outerRadius": 500, - "theme": { - "name": "五行配色主题", - "colorPalettes": { - "黑": "#000000", - "灰": "#757575", - "白": "#ffffff", - "木": "#43A047", - "火": "#E53935", - "土": "#8D6E63", - "金": "#78909C", - "水": "#0288D1", - "热": "#FF8F00", - "冷": "#1976D2", - "强": "#D32F2F", - "\u8f6f": "#FFE0B2" - } - }, + "themeRef": "五行弱", "layers": [ { "type": "centerIcon", @@ -38,11 +26,12 @@ "sectors": [ { "content": "阴", + "colorRef": "黑", "innerFill": 1 }, { "content": "阳", - "colorRef": "White", + "colorRef": "白", "innerFill": 0 } ] @@ -150,8 +139,8 @@ "startAngle": -4.5, "innerFill": 0, "colorRef": "火", - "num": 3, - "interval": 2, + "num": 4, + "interval": 1, "groupSplit": false }, { diff --git a/public/demo3.json b/public/demo3.json new file mode 100644 index 0000000..7028a0c --- /dev/null +++ b/public/demo3.json @@ -0,0 +1,160 @@ +{ + "name": "demo", + "description": "luopan demo config with named color palettes", + "background": "白", + "strokeWidth": 1, + "strokeOpacity": 1, + "strokeColor": "黑", + "insetDistance": 1, + "themeRef": "五行弱", + "layers": [ + { + "type": "centerIcon", + "centerIcon": { + "rIcon": 50, + "opacity": 0.8, + "name": "centericon.svg" + } + }, + { + "divisions": 2, + "rInner": 60, + "rOuter": 100, + "startAngle": 0, + "sectors": [ + { + "content": "阴", + "colorRef": "黑" + }, + { + "content": "阳", + "colorRef": "白" + } + ] + }, + { + "divisions": 8, + "rInner": 120, + "rOuter": 160, + "startAngle": 0, + "colorRef": "水", + "sectors": [ + { "content": "乾", "innerFill": 1 }, + { "content": "兑", "innerFill": 0 }, + { "content": "离", "innerFill": 1 }, + { "content": "震", "innerFill": 0 }, + { "content": "巽", "innerFill": 1 }, + { "content": "坎", "innerFill": 0 }, + { "content": "艮", "innerFill": 1 }, + { "content": "坤", "innerFill": 0 } + ] + }, + { + "divisions": 12, + "rInner": 160, + "rOuter": 200, + "startAngle": 0, + "colorRef": "土", + "num": 3, + "interval": 1, + "sectors": [ + { "content": "子", "colorRef": "水", "innerFill": 1 }, + { "content": "丑" }, + { "content": "寅", "colorRef": "木", "innerFill": 0 }, + { "content": "卯", "colorRef": "木", "innerFill": 1 }, + { "content": "辰" }, + { "content": "巳", "colorRef": "火", "innerFill": 1 }, + { "content": "午", "colorRef": "火", "innerFill": 0 }, + { "content": "未", "innerFill": 1 }, + { "content": "申", "colorRef": "金", "innerFill": 0 }, + { "content": "酉", "colorRef": "金", "innerFill": 1 }, + { "content": "戌" }, + { "content": "亥", "innerFill": 0 } + ] + }, + { + "divisions": 24, + "rInner": 200, + "rOuter": 240, + "startAngle": 0, + "sectors": [ + { "content": "甲乙|子|丙丁", "colorRef": "木", "innerFill": 1 }, + { "content": "丑" }, + { "content": "戊己|寅|庚辛", "colorRef": "土", "innerFill": 0 }, + { "content": "卯" }, + { "content": "壬癸|辰|甲乙", "innerFill": 1 }, + { "content": "巳" }, + { "content": "丙丁|午|戊己", "colorRef": "火", "innerFill": 0 }, + { "content": "未" }, + { "content": "庚辛|申|壬癸", "colorRef": "金", "innerFill": 1 }, + { "content": "酉" }, + { "content": "甲乙|戌|丙丁", "innerFill": 0 }, + { "content": "亥" }, + { "content": "戊己|子|庚辛" }, + { "content": "丑" }, + { "content": "壬癸|寅|甲乙" }, + { "content": "卯" }, + { "content": "丙丁|辰|戊己" }, + { "content": "巳" }, + { "content": "庚辛|午|壬癸" }, + { "content": "未" }, + { "content": "甲乙|申|丙丁" }, + { "content": "酉" }, + { "content": "戊己|戌|庚辛" }, + { "content": "亥" } + ] + }, + { + "divisions": 16, + "rInner": 250, + "rOuter": 270, + "startAngle": 0, + "sectors": [ + { "content": "甲乙|丙丁|戊己|庚辛", "colorRef": "木", "innerFill": 1 }, + { "content": "壬癸|甲乙|丙丁|戊己", "colorRef": "土", "innerFill": 0 }, + { "content": "庚辛|壬癸|甲乙|丙丁", "innerFill": 1 }, + { "content": "戊己|庚辛|壬癸|甲乙", "colorRef": "火", "innerFill": 0 }, + { "content": "丙丁|戊己|庚辛|壬癸", "colorRef": "金", "innerFill": 1 }, + { "content": "子丑|寅卯|辰巳|午未", "innerFill": 0 }, + { "content": "申酉|戌亥|子丑|寅卯", "colorRef": "木", "innerFill": 1 }, + { "content": "辰巳|午未|申酉|戌亥", "colorRef": "水", "innerFill": 0 }, + { "content": "甲乙|丙丁|戊己|庚辛", "innerFill": 1 }, + { "content": "壬癸|甲乙|丙丁|戊己", "colorRef": "土", "innerFill": 0 }, + { "content": "庚辛|壬癸|甲乙|丙丁", "colorRef": "木", "innerFill": 1 }, + { "content": "戊己|庚辛|壬癸|甲乙", "innerFill": 0 }, + { "content": "丙丁|戊己|庚辛|壬癸", "colorRef": "火", "innerFill": 1 }, + { "content": "子丑|寅卯|辰巳|午未", "colorRef": "金", "innerFill": 0 }, + { "content": "申酉|戌亥|子丑|寅卯", "innerFill": 1 }, + { "content": "辰巳|午未|申酉|戌亥", "colorRef": "水", "innerFill": 0 } + ] + }, + { + "divisions": 120, + "rInner": 300, + "rOuter": 310, + "startAngle": -4.5, + "innerFill": 0, + "colorRef": "火", + "num": 3, + "interval": 2, + "groupSplit": false + }, + { + "type": "degreeRing", + "degreeRing": { + "rInner": 350, + "rOuter": 380, + "showDegree": 1, + "mode": "both", + "opacity": 1, + "tickLength": 6, + "tickLengthStep": 2, + "majorTick": 10, + "minorTick": 5, + "microTick": 1, + "tickColor": "#000000", + "ringColor": "#000000" + } + } + ] +} diff --git a/public/luopan-configs.json b/public/luopan-configs.json new file mode 100644 index 0000000..8eff555 --- /dev/null +++ b/public/luopan-configs.json @@ -0,0 +1,21 @@ +{ + "default": "demo.json", + "items": [ + { + "name": "样式测试1", + "path": "/demo.json" + }, + { + "name": "样式测试2", + "path": "/demo2.json" + }, + { + "name": "样式测试3", + "path": "/demo3.json" + }, + { + "name": "入门罗盘", + "path": "/rumen.json" + } + ] +} diff --git a/public/rumen.json b/public/rumen.json new file mode 100644 index 0000000..a0bcd8c --- /dev/null +++ b/public/rumen.json @@ -0,0 +1,162 @@ +{ + "name": "rumen", + "description": "luopan rumen config", + "background": "金", + "strokeWidth": 1, + "strokeOpacity": 1, + "strokeColor": "黑", + "insetDistance": 1, + "themeRef": "五行弱", + "layers": [ + { + "type": "centerIcon", + "centerIcon": { + "rIcon": 50, + "opacity": 0.8, + "name": "centericon.svg" + } + }, + { + "divisions": 2, + "rInner": 60, + "rOuter": 100, + "startAngle": 0, + "sectors": [ + { + "content": "阴", + "colorRef": "黑" + }, + { + "content": "阳", + "colorRef": "白" + } + ] + }, + { + "divisions": 8, + "rInner": 120, + "rOuter": 160, + "startAngle": 0, + "sectors": [ + { "content": "乾", "colorRef": "火", "innerFill": 1 }, + { "content": "兑", "colorRef": "冷", "innerFill": 0 }, + { "content": "离", "colorRef": "火", "innerFill": 1 }, + { "content": "震", "colorRef": "木", "innerFill": 0 }, + { "content": "巽", "colorRef": "木", "innerFill": 1 }, + { "content": "坎", "colorRef": "冷", "innerFill": 0 }, + { "content": "艮", "colorRef": "强", "innerFill": 1 }, + { "content": "坤", "colorRef": "土", "innerFill": 0 } + ] + }, + { + "divisions": 12, + "rInner": 160, + "rOuter": 200, + "startAngle": 0, + "colorRef": "金", + "num": 3, + "interval": 1, + "sectors": [ + { "content": "子", "colorRef": "水", "innerFill": 1 }, + { "content": "丑" }, + { "content": "寅", "colorRef": "木", "innerFill": 0 }, + { "content": "卯", "colorRef": "木", "innerFill": 1 }, + { "content": "辰" }, + { "content": "巳", "colorRef": "火", "innerFill": 1 }, + { "content": "午", "colorRef": "火", "innerFill": 0 }, + { "content": "未", "innerFill": 1 }, + { "content": "申", "colorRef": "金", "innerFill": 0 }, + { "content": "酉", "colorRef": "金", "innerFill": 1 }, + { "content": "戌" }, + { "content": "亥", "innerFill": 0 } + ] + }, + { + "divisions": 24, + "rInner": 200, + "rOuter": 240, + "startAngle": 0, + "colorRef": "金", + "num": 2, + "interval": 1, + "sectors": [ + { "content": "甲乙|子|丙丁", "colorRef": "木", "innerFill": 1 }, + { "content": "丑" }, + { "content": "戊己|寅|庚辛", "colorRef": "土", "innerFill": 0 }, + { "content": "卯" }, + { "content": "壬癸|辰|甲乙", "innerFill": 1 }, + { "content": "巳" }, + { "content": "丙丁|午|戊己", "colorRef": "火", "innerFill": 0 }, + { "content": "未" }, + { "content": "庚辛|申|壬癸", "colorRef": "金", "innerFill": 1 }, + { "content": "酉" }, + { "content": "甲乙|戌|丙丁", "innerFill": 0 }, + { "content": "亥" }, + { "content": "戊己|子|庚辛" }, + { "content": "丑" }, + { "content": "壬癸|寅|甲乙" }, + { "content": "卯" }, + { "content": "丙丁|辰|戊己" }, + { "content": "巳" }, + { "content": "庚辛|午|壬癸" }, + { "content": "未" }, + { "content": "甲乙|申|丙丁" }, + { "content": "酉" }, + { "content": "戊己|戌|庚辛" }, + { "content": "亥" } + ] + }, + { + "divisions": 16, + "rInner": 250, + "rOuter": 270, + "startAngle": 0, + "sectors": [ + { "content": "甲乙|丙丁|戊己|庚辛", "colorRef": "木", "innerFill": 1 }, + { "content": "壬癸|甲乙|丙丁|戊己", "colorRef": "土", "innerFill": 0 }, + { "content": "庚辛|壬癸|甲乙|丙丁", "innerFill": 1 }, + { "content": "戊己|庚辛|壬癸|甲乙", "colorRef": "火", "innerFill": 0 }, + { "content": "丙丁|戊己|庚辛|壬癸", "colorRef": "金", "innerFill": 1 }, + { "content": "子丑|寅卯|辰巳|午未", "innerFill": 0 }, + { "content": "申酉|戌亥|子丑|寅卯", "colorRef": "木", "innerFill": 1 }, + { "content": "辰巳|午未|申酉|戌亥", "colorRef": "水", "innerFill": 0 }, + { "content": "甲乙|丙丁|戊己|庚辛", "innerFill": 1 }, + { "content": "壬癸|甲乙|丙丁|戊己", "colorRef": "土", "innerFill": 0 }, + { "content": "庚辛|壬癸|甲乙|丙丁", "colorRef": "木", "innerFill": 1 }, + { "content": "戊己|庚辛|壬癸|甲乙", "innerFill": 0 }, + { "content": "丙丁|戊己|庚辛|壬癸", "colorRef": "火", "innerFill": 1 }, + { "content": "子丑|寅卯|辰巳|午未", "colorRef": "金", "innerFill": 0 }, + { "content": "申酉|戌亥|子丑|寅卯", "innerFill": 1 }, + { "content": "辰巳|午未|申酉|戌亥", "colorRef": "水", "innerFill": 0 } + ] + }, + { + "divisions": 120, + "rInner": 300, + "rOuter": 310, + "startAngle": -4.5, + "innerFill": 0, + "colorRef": "火", + "num": 3, + "interval": 2, + "groupSplit": false + }, + { + "type": "degreeRing", + "degreeRing": { + "rInner": 350, + "rOuter": 380, + "showDegree": 1, + "mode": "both", + "opacity": 1, + "tickLength": 6, + "tickLengthStep": 2, + "majorTick": 10, + "minorTick": 5, + "microTick": 1, + "tickColor": "#000000", + "ringColor": "#000000" + } + } + ] +} diff --git a/public/themes.json b/public/themes.json new file mode 100644 index 0000000..89132de --- /dev/null +++ b/public/themes.json @@ -0,0 +1,174 @@ +{ + "default": "五行强", + "items": [ + { + "name": "五行强", + "colorPalettes": { + "黑": "#000000", + "灰": "#757575", + "白": "#ffffff", + "木": "#43A047", + "火": "#E53935", + "土": "#8D6E63", + "金": "#D4AF37", + "水": "#0288D1", + "热": "#FF8F00", + "冷": "#1976D2", + "强": "#D32F2F", + "软": "#FFE0B2" + } + }, + { + "name": "五行弱", + "colorPalettes": { + "黑": "#000000", + "灰": "#DADADA", + "白": "#ffffff", + "木": "#2A6B2D", + "火": "#C44846", + "土": "#A57563", + "金": "#E7D238", + "水": "#1E7BAC", + "热": "#FF8F00", + "冷": "#1976D2", + "强": "#FF0000", + "弱": "#EFD272" + } + }, + { + "name": "晨曦", + "colorPalettes": { + "霞光": "#FFB997", + "暖金": "#FFC857", + "薄雾": "#E6EFF6", + "嫩绿": "#A8E6CE", + "朝蓝": "#7AC7E3", + "珊红": "#FF6B6B", + "砂色": "#D9B99B", + "云白": "#FFFFFF", + "影灰": "#7D7F87", + "墨蓝": "#2A3D66" + } + }, + { + "name": "暮色", + "colorPalettes": { + "暮紫": "#6C5B7B", + "深蓝": "#283149", + "暮橙": "#FF914D", + "黯灰": "#5D5D66", + "暗玉": "#2E8B7C", + "烟蓝": "#4B6F86", + "月白": "#F2F6F8", + "铜黄": "#C08F35", + "绛红": "#A23E48", + "夜黑": "#0B0F1A" + } + }, + { + "name": "海风", + "colorPalettes": { + "海蓝": "#0077B6", + "浅滩": "#EAF6F6", + "浪白": "#F7FCFF", + "蔚蓝": "#00B4D8", + "青绿": "#2EC4B6", + "碧玉": "#118AB2", + "珊粉": "#FF7A7A", + "深海": "#023E8A", + "泡沫": "#CFF7F3", + "夕珊": "#FFB4A2" + } + }, + { + "name": "砂岩", + "colorPalettes": { + "砂黄": "#DDB892", + "土褐": "#A67C52", + "岩灰": "#8A8776", + "日黄": "#FFDA77", + "褐红": "#A65E3B", + "朽木": "#C7B299", + "石白": "#F5F3EE", + "暮砂": "#BFAE9D", + "土灰": "#9E8F80", + "暗褐": "#5C3A21" + } + }, + { + "name": "森林", + "colorPalettes": { + "树绿": "#2F7A1F", + "苔绿": "#69995B", + "深绿": "#1B4636", + "叶黄": "#C8D44B", + "泥褐": "#7C5A3A", + "树皮": "#6A4C3B", + "莹绿": "#9FD89B", + "林影": "#254117", + "嫩叶": "#B7E4A6", + "藤蔓": "#3B6B35" + } + }, + { + "name": "霓虹", + "colorPalettes": { + "电青": "#00F5D4", + "霓粉": "#FF6AC1", + "紫光": "#9D4EDD", + "亮黄": "#FFD60A", + "霓橙": "#FF7A00", + "洋红": "#FF007F", + "亮蓝": "#00A3FF", + "霓绿": "#41F582", + "黑底": "#0A0A0A", + "白晕": "#F8F8FF" + } + }, + { + "name": "芙蓉", + "colorPalettes": { + "芙粉": "#FADCD9", + "荷绿": "#9BD7C6", + "莲白": "#FFF7F3", + "柔紫": "#E9D6FF", + "粉橙": "#FFD1BA", + "浅灰": "#E6E6E6", + "香黄": "#FFE9A8", + "薄荷": "#BCEBCB", + "桃红": "#FF94A6", + "雾蓝": "#DDECF7" + } + }, + { + "name": "墨韵", + "colorPalettes": { + "墨黑": "#0B0B0B", + "浓灰": "#4A4A4A", + "烟白": "#F5F5F5", + "石墨": "#2E2E2E", + "青黛": "#1F6F8B", + "皓白": "#FFFFFF", + "墨蓝": "#14213D", + "暗灰": "#6B6B6B", + "笔褐": "#5B4B3A", + "玄青": "#0F4C5C" + } + }, + { + "name": "灰阶", + "colorPalettes": { + "墨灰": "#0B0B0B", + "深灰": "#2F2F2F", + "石灰": "#595959", + "烟灰": "#808080", + "中灰": "#A0A0A0", + "银灰": "#C0C0C0", + "雾灰": "#D9D9D9", + "亮灰": "#EAEAEA", + "浅灰": "#F5F5F5", + "乳白": "#FFFFFF" + } + } + ] +} diff --git a/refactor-plan.md b/refactor-plan.md index cdc220b..eaeddb4 100644 --- a/refactor-plan.md +++ b/refactor-plan.md @@ -17,15 +17,91 @@ **核心变化:** 1. **配置驱动**:从 JSON 配置文件完全定义罗盘结构 2. **新增罗盘零改码**:新增罗盘只需在 `public/` 下增加 JSON 配置文件,无需修改代码 -3. **复杂着色规则**:支持三级着色优先级(全局 → 层级规律填色 → 扇区独立) -4. **多文本单元**:扇区内容支持 `|` 分隔的多个文本单元,角度智能分配 -5. **SVG 图标支持**:扇区内容可以是 SVG 文件 -6. **中心图标**:作为 layer 类型,支持可旋转的中心 SVG 图标 -7. **360度刻度环**:作为 layer 类型,支持多种刻度模式的度数环 -8. **命名配色方案**:通过 theme.colorPalettes 定义可复用颜色 -9. **规律填色机制**:通过 num + interval 实现周期性着色 -10. **同组分割线控制**:groupSplit 参数控制组内分割线显示 -11. **外半径兜底**:默认使用 layers 最大 rOuter,outerRadius 仅作为无层配置时的兜底 +3. **配置下拉切换**:下拉菜单可选择 `public/` 下的配置(如 `demo.json`、`demo2.json`)切换罗盘 +4. **复杂着色规则**:支持三级着色优先级(全局 → 层级规律填色 → 扇区独立) +5. **多文本单元**:扇区内容支持 `|` 分隔的多个文本单元,角度智能分配 +6. **多文本比例可配**:在每个 layer 中可配置多文本比例(用于 `|` 分隔内容的角度分配) +7. **SVG 图标支持**:扇区内容可以是 SVG 文件 +8. **中心图标**:作为 layer 类型,支持可旋转的中心 SVG 图标 +9. **360度刻度环**:作为 layer 类型,支持多种刻度模式的度数环 +10. **命名配色方案**:通过 theme.colorPalettes 定义可复用颜色 +11. **规律填色机制**:通过 num + interval 实现周期性着色 +12. **同组分割线控制**:groupSplit 参数控制组内分割线显示 +13. **外半径兜底**:默认使用 layers 最大 rOuter,outerRadius 仅作为无层配置时的兜底 + +### 1.3 配置清单与切换机制(新增) + +**问题:** 运行时无法直接读取 `public/` 目录文件列表,因此下拉菜单需要“配置清单”或“构建期生成清单”。 + +**推荐方案(满足“新增罗盘只需增加 JSON 文件”):** +1. **清单文件:** 构建期生成 `public/luopan-configs.json`,包含可选配置列表与默认项。 +2. **生成逻辑:** 扫描 `public/` 下的 `*.json`,排除 `*.json.conf` 和 `luopan-configs.json` 本身。 +3. **示例格式:** + ```json + { + "default": "demo.json", + "items": [ + { "name": "示例罗盘一", "path": "/demo.json" }, + { "name": "示例罗盘二", "path": "/demo2.json" } + ] + } + ``` +4. **前端加载:** `Luopan.vue` 启动时拉取该清单,渲染下拉选项。 +5. **切换逻辑:** 选择项变化时更新 `configPath` 并触发重新加载;同步更新 URL `?config=xxx.json` 便于分享。 +6. **新增配置:** 仅需在 `public/` 放入新的 `*.json`,清单会在构建/开发启动时自动更新。 + +**备用方案(不启用生成脚本):** 手动维护 `public/luopan-configs.json`,仍然无需改代码,但需追加清单条目。 + +### 1.4 主题抽离与引用(新增) + +**目标:** 罗盘配置通过 `themeRef` 引用统一的 `themes.json`,不再内嵌 theme。 + +**主题文件结构(public/themes.json):** +```json +{ + "default": "五行", + "items": [ + { + "name": "五行", + "colorPalettes": { + "黑": "#000000", + "灰": "#757575" + } + } + ] +} +``` + +**罗盘 JSON 使用方式:** +```json +{ + "name": "demo", + "background": "白", + "themeRef": "五行", + "layers": [] +} +``` + +**解析规则:** +1. 如果配置包含 `themeRef`,优先使用对应主题。 +2. 若未指定 `themeRef`,使用 `themes.json.default`。 +3. 若 `themeRef` 或 `default` 不存在:抛出配置错误(或回退到空主题,需在实现中约定)。 + +**实现改动点:** +1. `types.ts`: + - `LuopanConfig.theme` 变为可选 + - 新增 `themeRef?: string` +2. `configParser.ts`: + - 支持解析 `themeRef` + - 当 `theme` 缺失时暂不报错,由上层注入主题 +3. `useLuopan.ts`: + - 读取 `public/themes.json` + - 根据 `themeRef/default` 注入主题到配置 + - 处理错误与回退 +4. 示例与文档: + - `public/demo*.json` 替换为 `themeRef` + - 新增 `public/themes.json` + - 更新 `demo.json.conf` 说明 --- @@ -148,15 +224,17 @@ function applyPatternColoring( } ``` -**多文本单元角度分配:** +**多文本单元角度分配(支持 unitRatios):** ```typescript function splitMultiTextUnits( content: string, aStart: number, - aEnd: number + aEnd: number, + unitRatios?: number[] ): TextUnit[] { const units = content.split('|'); - const ratios = getLayoutRatio(units.length); // 从 constants.ts + const ratios = normalizeRatios(unitRatios, units.length) + ?? getLayoutRatio(units.length); // 从 constants.ts const totalAngle = aEnd - aStart; const textUnits: TextUnit[] = []; @@ -174,6 +252,27 @@ function splitMultiTextUnits( return textUnits; } + +function normalizeRatios( + ratios: number[] | undefined, + count: number +): number[] | null { + if (!ratios || ratios.length !== count) return null; + if (ratios.some((value) => typeof value !== 'number' || value <= 0)) return null; + const sum = ratios.reduce((acc, value) => acc + value, 0); + if (sum <= 0) return null; + return ratios.map((value) => value / sum); +} +``` + +**示例(layer 级别配置比例):** +```json +{ + "divisions": 24, + "rInner": 200, + "rOuter": 240, + "unitRatios": [0.25, 0.5, 0.25] +} ``` --- @@ -243,6 +342,7 @@ export interface SectorLayerConfig { startAngle?: number; colorRef?: string; innerFill?: 0 | 1; + unitRatios?: number[]; // 多文本单元比例(对应 content 用 "|" 分隔) num?: number; interval?: number; groupSplit?: boolean; @@ -429,6 +529,7 @@ export class ColorResolver { - splitMultiTextUnits() 函数 - 角度分配逻辑 - SVG 文件检测 + - 支持 layer.unitRatios 覆盖默认比例 2. ✅ 更新 `utils.ts`: - 适配多文本单元的路径生成 - 字体大小计算调整 @@ -674,7 +775,7 @@ export function buildDegreeRing(config: DegreeRingConfig): { - 调用各个解析器和构建器 - 返回完整渲染数据 2. ✅ 更新 `Luopan.vue`: - - 移除示例选择器 + - 使用配置下拉替换示例选择器(可切换 `public/*.json`) - 添加配置加载界面 - 渲染多文本单元 - 渲染刻度环 @@ -1179,4 +1280,3 @@ describe('完整渲染流程', () => { --- **本重构方案完全基于现有代码和需求文档制定,确保可行性和可执行性。建议按阶段逐步实施,每个阶段完成后进行验收,确保质量和进度。** - diff --git a/src/Luopan.vue b/src/Luopan.vue index 7627c5e..4e9e367 100644 --- a/src/Luopan.vue +++ b/src/Luopan.vue @@ -2,6 +2,19 @@
+ +