update at 2026-01-28 16:45:27
This commit is contained in:
327
public/demo.json
327
public/demo.json
@@ -39,14 +39,38 @@
|
||||
"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 }
|
||||
{
|
||||
"content": "乾",
|
||||
"innerFill": 1
|
||||
},
|
||||
{
|
||||
"content": "兑",
|
||||
"innerFill": 0
|
||||
},
|
||||
{
|
||||
"content": "离",
|
||||
"innerFill": 1
|
||||
},
|
||||
{
|
||||
"content": "震",
|
||||
"innerFill": 0
|
||||
},
|
||||
{
|
||||
"content": "巽",
|
||||
"innerFill": 1
|
||||
},
|
||||
{
|
||||
"content": "坎",
|
||||
"innerFill": 0
|
||||
},
|
||||
{
|
||||
"content": "艮",
|
||||
"innerFill": 1
|
||||
},
|
||||
{
|
||||
"content": "坤",
|
||||
"innerFill": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -58,18 +82,58 @@
|
||||
"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 }
|
||||
{
|
||||
"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
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -78,30 +142,88 @@
|
||||
"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": "亥" }
|
||||
{
|
||||
"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": "亥"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -110,22 +232,81 @@
|
||||
"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 }
|
||||
{
|
||||
"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
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -141,20 +322,18 @@
|
||||
},
|
||||
{
|
||||
"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"
|
||||
}
|
||||
"rInner": 350,
|
||||
"rOuter": 380,
|
||||
"showDegree": 1,
|
||||
"mode": "both",
|
||||
"opacity": 1,
|
||||
"tickLength": 6,
|
||||
"tickLengthStep": 2,
|
||||
"majorTick": 10,
|
||||
"minorTick": 5,
|
||||
"microTick": 1,
|
||||
"tickColor": "#000000",
|
||||
"ringColor": "#000000"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
"rInner": 60,
|
||||
"rOuter": 90,
|
||||
"startAngle": 0,
|
||||
|
||||
"sectors": [
|
||||
{
|
||||
"content": "阴",
|
||||
@@ -42,14 +41,38 @@
|
||||
"rOuter": 160,
|
||||
"startAngle": 0,
|
||||
"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 }
|
||||
{
|
||||
"content": "乾",
|
||||
"innerFill": 1
|
||||
},
|
||||
{
|
||||
"content": "兑",
|
||||
"innerFill": 0
|
||||
},
|
||||
{
|
||||
"content": "离",
|
||||
"innerFill": 1
|
||||
},
|
||||
{
|
||||
"content": "震",
|
||||
"innerFill": 0
|
||||
},
|
||||
{
|
||||
"content": "巽",
|
||||
"innerFill": 1
|
||||
},
|
||||
{
|
||||
"content": "坎",
|
||||
"innerFill": 0
|
||||
},
|
||||
{
|
||||
"content": "艮",
|
||||
"innerFill": 1
|
||||
},
|
||||
{
|
||||
"content": "坤",
|
||||
"innerFill": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -62,18 +85,58 @@
|
||||
"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 }
|
||||
{
|
||||
"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
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -82,30 +145,88 @@
|
||||
"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": "亥" }
|
||||
{
|
||||
"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": "亥"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -114,22 +235,81 @@
|
||||
"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 }
|
||||
{
|
||||
"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
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -145,19 +325,17 @@
|
||||
},
|
||||
{
|
||||
"type": "degreeRing",
|
||||
"degreeRing": {
|
||||
"rInner": 450,
|
||||
"rOuter": 500,
|
||||
"showDegree": 1,
|
||||
"mode": "both",
|
||||
"opacity": 0.3,
|
||||
"tickLength": 6,
|
||||
"majorTick": 10,
|
||||
"minorTick": 5,
|
||||
"microTick": 1,
|
||||
"tickColor": "#ffffff",
|
||||
"ringColor": "#ffffff"
|
||||
}
|
||||
"rInner": 450,
|
||||
"rOuter": 500,
|
||||
"showDegree": 1,
|
||||
"mode": "both",
|
||||
"opacity": 0.3,
|
||||
"tickLength": 6,
|
||||
"majorTick": 10,
|
||||
"minorTick": 5,
|
||||
"microTick": 1,
|
||||
"tickColor": "#ffffff",
|
||||
"ringColor": "#ffffff"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -39,14 +39,38 @@
|
||||
"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 }
|
||||
{
|
||||
"content": "乾",
|
||||
"innerFill": 1
|
||||
},
|
||||
{
|
||||
"content": "兑",
|
||||
"innerFill": 0
|
||||
},
|
||||
{
|
||||
"content": "离",
|
||||
"innerFill": 1
|
||||
},
|
||||
{
|
||||
"content": "震",
|
||||
"innerFill": 0
|
||||
},
|
||||
{
|
||||
"content": "巽",
|
||||
"innerFill": 1
|
||||
},
|
||||
{
|
||||
"content": "坎",
|
||||
"innerFill": 0
|
||||
},
|
||||
{
|
||||
"content": "艮",
|
||||
"innerFill": 1
|
||||
},
|
||||
{
|
||||
"content": "坤",
|
||||
"innerFill": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -58,18 +82,58 @@
|
||||
"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 }
|
||||
{
|
||||
"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
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -78,30 +142,88 @@
|
||||
"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": "亥" }
|
||||
{
|
||||
"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": "亥"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -110,22 +232,81 @@
|
||||
"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 }
|
||||
{
|
||||
"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
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -141,20 +322,18 @@
|
||||
},
|
||||
{
|
||||
"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"
|
||||
}
|
||||
"rInner": 350,
|
||||
"rOuter": 380,
|
||||
"showDegree": 1,
|
||||
"mode": "both",
|
||||
"opacity": 1,
|
||||
"tickLength": 6,
|
||||
"tickLengthStep": 2,
|
||||
"majorTick": 10,
|
||||
"minorTick": 5,
|
||||
"microTick": 1,
|
||||
"tickColor": "#000000",
|
||||
"ringColor": "#000000"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
4540
public/fengshui.json
4540
public/fengshui.json
File diff suppressed because one or more lines are too long
3766
public/fengshui10.json
Normal file
3766
public/fengshui10.json
Normal file
File diff suppressed because it is too large
Load Diff
3768
public/fengshui2.json
Normal file
3768
public/fengshui2.json
Normal file
File diff suppressed because it is too large
Load Diff
3768
public/fengshui3.json
Normal file
3768
public/fengshui3.json
Normal file
File diff suppressed because it is too large
Load Diff
3768
public/fengshui4.json
Normal file
3768
public/fengshui4.json
Normal file
File diff suppressed because it is too large
Load Diff
3768
public/fengshui5.json
Normal file
3768
public/fengshui5.json
Normal file
File diff suppressed because it is too large
Load Diff
3768
public/fengshui6.json
Normal file
3768
public/fengshui6.json
Normal file
File diff suppressed because it is too large
Load Diff
3768
public/fengshui7.json
Normal file
3768
public/fengshui7.json
Normal file
File diff suppressed because it is too large
Load Diff
3768
public/fengshui8.json
Normal file
3768
public/fengshui8.json
Normal file
File diff suppressed because it is too large
Load Diff
3768
public/fengshui9.json
Normal file
3768
public/fengshui9.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -20,6 +20,42 @@
|
||||
{
|
||||
"name": "fengshui",
|
||||
"path": "/fengshui.json"
|
||||
},
|
||||
{
|
||||
"name": "fengshui2",
|
||||
"path": "/fengshui2.json"
|
||||
},
|
||||
{
|
||||
"name": "fengshui3",
|
||||
"path": "/fengshui3.json"
|
||||
},
|
||||
{
|
||||
"name": "fengshui4",
|
||||
"path": "/fengshui4.json"
|
||||
},
|
||||
{
|
||||
"name": "fengshui5",
|
||||
"path": "/fengshui5.json"
|
||||
},
|
||||
{
|
||||
"name": "fengshui6",
|
||||
"path": "/fengshui6.json"
|
||||
},
|
||||
{
|
||||
"name": "fengshui7",
|
||||
"path": "/fengshui7.json"
|
||||
},
|
||||
{
|
||||
"name": "fengshui8",
|
||||
"path": "/fengshui8.json"
|
||||
},
|
||||
{
|
||||
"name": "fengshui9",
|
||||
"path": "/fengshui9.json"
|
||||
},
|
||||
{
|
||||
"name": "fengshui10",
|
||||
"path": "/fengshui10.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -38,14 +38,46 @@
|
||||
"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 }
|
||||
{
|
||||
"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
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -57,18 +89,58 @@
|
||||
"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 }
|
||||
{
|
||||
"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
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -80,30 +152,88 @@
|
||||
"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": "亥" }
|
||||
{
|
||||
"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": "亥"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -112,22 +242,81 @@
|
||||
"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 }
|
||||
{
|
||||
"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
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -143,20 +332,18 @@
|
||||
},
|
||||
{
|
||||
"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"
|
||||
}
|
||||
"rInner": 350,
|
||||
"rOuter": 380,
|
||||
"showDegree": 1,
|
||||
"mode": "both",
|
||||
"opacity": 1,
|
||||
"tickLength": 6,
|
||||
"tickLengthStep": 2,
|
||||
"majorTick": 10,
|
||||
"minorTick": 5,
|
||||
"microTick": 1,
|
||||
"tickColor": "#000000",
|
||||
"ringColor": "#000000"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,5 +1,20 @@
|
||||
# 罗盘项目重构方案
|
||||
|
||||
## 0. 重构方案提要(先看这一段)
|
||||
|
||||
**目标:** 从“硬编码示例”升级到“配置驱动”的罗盘渲染系统,并为大罗盘性能优化留出清晰路径。
|
||||
**策略:** 先重构数据解析与渲染结构,再完善主题/多文本/刻度/中心图标,最后补齐测试与性能。
|
||||
**落地路径:**
|
||||
1) 解析层与类型统一(配置校验、主题、层级半径推导)。
|
||||
2) 扇区构建器与颜色引擎(含规律填色、groupSplit)。
|
||||
3) UI 适配(Luopan.vue、useLuopan 重构)。
|
||||
4) 测试与性能优化(含大罗盘拖拽优化计划 10.4)。
|
||||
|
||||
**预期产出:**
|
||||
- 新增/替换若干模块(configParser / colorResolver / sectorBuilder / degreeRing / centerIcon)。
|
||||
- `public/*.json` 配置即可新增罗盘,无需改代码。
|
||||
- 统一主题与颜色规则,支持复杂布局与 SVG 图标。
|
||||
|
||||
---
|
||||
|
||||
## 一、项目现状分析
|
||||
@@ -103,6 +118,22 @@
|
||||
- 新增 `public/themes.json`
|
||||
- 更新 `demo.json.conf` 说明
|
||||
|
||||
### 1.5 layerHeight 参数规则(新增)
|
||||
|
||||
**目标:** 支持在 layer 中以 `layerHeight` 定义厚度,并可自动推导 `rInner` / `rOuter`。
|
||||
|
||||
**规则:**
|
||||
1. 若 layer 同时指定 `rInner` 和 `rOuter`,则忽略 `layerHeight`。
|
||||
2. 若 layer 仅指定 `layerHeight`,且没有 `rInner` / `rOuter`:
|
||||
- 使用上一层的 `rOuter` 作为当前 `rInner`
|
||||
- 当前 `rOuter = 上一层 rOuter + layerHeight`
|
||||
3. 若 layer 未提供任何半径信息(`rInner` / `rOuter` / `layerHeight`),则视为配置错误(或按实现约定抛错/警告)。
|
||||
|
||||
**实现改动点:**
|
||||
1. `types.ts`:为 sector layer 增加可选字段 `layerHeight?: number`
|
||||
2. `configParser.ts`:新增“层半径归一化”步骤,按层顺序推导半径
|
||||
3. 文档/示例:补充 `layerHeight` 的说明与示例用法
|
||||
|
||||
---
|
||||
|
||||
## 二、整体架构设计
|
||||
|
||||
503
src/Luopan.vue
503
src/Luopan.vue
@@ -42,6 +42,7 @@
|
||||
<div
|
||||
v-else
|
||||
class="svg-container"
|
||||
:class="{ 'is-dragging': isDragging }"
|
||||
@wheel.prevent="handleWheel"
|
||||
@mousedown="handleMouseDown"
|
||||
@mousemove="handleMouseMove"
|
||||
@@ -53,252 +54,258 @@
|
||||
:height="size"
|
||||
:viewBox="`${viewBoxMin} ${viewBoxMin} ${viewBoxSize} ${viewBoxSize}`"
|
||||
class="svg"
|
||||
:style="{
|
||||
transform: `scale(${scale}) translate(${panX}px, ${panY}px)`,
|
||||
cursor: isDragging ? 'grabbing' : 'grab'
|
||||
}"
|
||||
>
|
||||
<!-- 背景 -->
|
||||
<circle
|
||||
:r="outerMost || viewBoxSize / 2"
|
||||
:fill="config?.background || '#ffffff'"
|
||||
/>
|
||||
|
||||
<g v-memo="[sectors]">
|
||||
<!-- 扇区 -->
|
||||
<g>
|
||||
<path
|
||||
v-for="s in sectors"
|
||||
:key="s.key"
|
||||
:d="s.path"
|
||||
:fill="s.fill"
|
||||
<g ref="viewport" class="viewport">
|
||||
<!-- 背景 -->
|
||||
<circle
|
||||
:r="outerMost || viewBoxSize / 2"
|
||||
:fill="config?.background || '#ffffff'"
|
||||
/>
|
||||
</g>
|
||||
|
||||
<!-- 内部填色区域 -->
|
||||
<g>
|
||||
<template v-for="s in sectors" :key="s.key + '-inner'">
|
||||
<path
|
||||
v-if="s.innerFillPath"
|
||||
:d="s.innerFillPath"
|
||||
:fill="s.innerFillColor"
|
||||
fill-opacity="1"
|
||||
stroke="none"
|
||||
/>
|
||||
</template>
|
||||
</g>
|
||||
<g v-memo="[sectors]">
|
||||
<!-- 扇区 -->
|
||||
<g>
|
||||
<path
|
||||
v-for="s in sectors"
|
||||
:key="s.key"
|
||||
:d="s.path"
|
||||
:fill="s.fill"
|
||||
/>
|
||||
</g>
|
||||
|
||||
<!-- 定义文字路径 -->
|
||||
<defs>
|
||||
<path
|
||||
v-for="s in sectors"
|
||||
:key="s.textPathId"
|
||||
:id="s.textPathId"
|
||||
:d="s.textPath"
|
||||
fill="none"
|
||||
/>
|
||||
<template v-for="s in sectors" :key="s.key + '-units'">
|
||||
<path
|
||||
v-for="unit in s.textUnits || []"
|
||||
:key="unit.textPathId"
|
||||
:id="unit.textPathId"
|
||||
:d="unit.textPath"
|
||||
<!-- 内部填色区域 -->
|
||||
<g>
|
||||
<template v-for="s in sectors" :key="s.key + '-inner'">
|
||||
<path
|
||||
v-if="s.innerFillPath"
|
||||
:d="s.innerFillPath"
|
||||
:fill="s.innerFillColor"
|
||||
fill-opacity="1"
|
||||
stroke="none"
|
||||
/>
|
||||
</template>
|
||||
</g>
|
||||
|
||||
<!-- 定义文字路径 -->
|
||||
<defs>
|
||||
<path
|
||||
v-for="s in sectors"
|
||||
:key="s.textPathId"
|
||||
:id="s.textPathId"
|
||||
:d="s.textPath"
|
||||
fill="none"
|
||||
/>
|
||||
<template v-for="s in sectors" :key="s.key + '-units'">
|
||||
<path
|
||||
v-for="unit in s.textUnits || []"
|
||||
:key="unit.textPathId"
|
||||
:id="unit.textPathId"
|
||||
:d="unit.textPath"
|
||||
fill="none"
|
||||
/>
|
||||
</template>
|
||||
</defs>
|
||||
|
||||
<!-- 文字标签(沿圆弧排列) -->
|
||||
<g>
|
||||
<template v-for="s in sectors" :key="s.key + '-text'">
|
||||
<template v-if="s.textUnits">
|
||||
<g v-for="unit in s.textUnits || []" :key="unit.textPathId">
|
||||
<text
|
||||
v-if="!unit.isSvg"
|
||||
:font-size="unit.fontSize"
|
||||
:fill="s.textColor"
|
||||
:writing-mode="unit.isVertical ? 'tb' : undefined"
|
||||
:glyph-orientation-vertical="unit.isVertical ? '0' : undefined"
|
||||
:text-anchor="unit.isVertical ? 'middle' : undefined"
|
||||
style="user-select: none"
|
||||
>
|
||||
<textPath
|
||||
:href="'#' + unit.textPathId"
|
||||
startOffset="50%"
|
||||
text-anchor="middle"
|
||||
dominant-baseline="central"
|
||||
>
|
||||
{{ unit.content }}
|
||||
</textPath>
|
||||
</text>
|
||||
<image
|
||||
v-else
|
||||
:href="unit.svgPath"
|
||||
:x="getUnitSvgBox(s, unit).x"
|
||||
:y="getUnitSvgBox(s, unit).y"
|
||||
:width="getUnitSvgBox(s, unit).size"
|
||||
:height="getUnitSvgBox(s, unit).size"
|
||||
:opacity="s.textColor ? 1 : 1"
|
||||
/>
|
||||
</g>
|
||||
</template>
|
||||
<template v-else>
|
||||
<text
|
||||
v-if="!s.isSvgContent"
|
||||
:font-size="s.fontSize"
|
||||
:fill="s.textColor"
|
||||
:writing-mode="s.isVertical ? 'tb' : undefined"
|
||||
:glyph-orientation-vertical="s.isVertical ? '0' : undefined"
|
||||
:text-anchor="s.isVertical ? 'middle' : undefined"
|
||||
style="user-select: none"
|
||||
>
|
||||
<textPath
|
||||
:href="'#' + s.textPathId"
|
||||
startOffset="50%"
|
||||
text-anchor="middle"
|
||||
dominant-baseline="central"
|
||||
>
|
||||
{{ s.label }}
|
||||
</textPath>
|
||||
</text>
|
||||
<image
|
||||
v-else
|
||||
:href="s.svgPath"
|
||||
:x="getSectorSvgBox(s).x"
|
||||
:y="getSectorSvgBox(s).y"
|
||||
:width="getSectorSvgBox(s).size"
|
||||
:height="getSectorSvgBox(s).size"
|
||||
/>
|
||||
</template>
|
||||
|
||||
</template>
|
||||
</g>
|
||||
</g>
|
||||
|
||||
<!-- 扇区边界线 -->
|
||||
<g
|
||||
v-memo="[sectors, boundaryRings, strokeColor, strokeOpacity, strokeWidth]"
|
||||
:stroke="strokeColor"
|
||||
:stroke-opacity="strokeOpacity"
|
||||
:stroke-width="strokeWidth"
|
||||
>
|
||||
<circle
|
||||
v-for="r in boundaryRings"
|
||||
:key="'ring-outline-' + r"
|
||||
:r="r"
|
||||
fill="none"
|
||||
/>
|
||||
</template>
|
||||
</defs>
|
||||
|
||||
<!-- 文字标签(沿圆弧排列) -->
|
||||
<g>
|
||||
<template v-for="s in sectors" :key="s.key + '-text'">
|
||||
<template v-if="s.textUnits">
|
||||
<g v-for="unit in s.textUnits || []" :key="unit.textPathId">
|
||||
<text
|
||||
v-if="!unit.isSvg"
|
||||
:font-size="unit.fontSize"
|
||||
:fill="s.textColor"
|
||||
:writing-mode="unit.isVertical ? 'tb' : undefined"
|
||||
:glyph-orientation-vertical="unit.isVertical ? '0' : undefined"
|
||||
:text-anchor="unit.isVertical ? 'middle' : undefined"
|
||||
style="user-select: none"
|
||||
>
|
||||
<textPath
|
||||
:href="'#' + unit.textPathId"
|
||||
startOffset="50%"
|
||||
text-anchor="middle"
|
||||
dominant-baseline="central"
|
||||
>
|
||||
{{ unit.content }}
|
||||
</textPath>
|
||||
</text>
|
||||
<image
|
||||
v-else
|
||||
:href="unit.svgPath"
|
||||
:x="getUnitSvgBox(s, unit).x"
|
||||
:y="getUnitSvgBox(s, unit).y"
|
||||
:width="getUnitSvgBox(s, unit).size"
|
||||
:height="getUnitSvgBox(s, unit).size"
|
||||
:opacity="s.textColor ? 1 : 1"
|
||||
/>
|
||||
</g>
|
||||
</template>
|
||||
<template v-else>
|
||||
<text
|
||||
v-if="!s.isSvgContent"
|
||||
:font-size="s.fontSize"
|
||||
:fill="s.textColor"
|
||||
:writing-mode="s.isVertical ? 'tb' : undefined"
|
||||
:glyph-orientation-vertical="s.isVertical ? '0' : undefined"
|
||||
:text-anchor="s.isVertical ? 'middle' : undefined"
|
||||
style="user-select: none"
|
||||
>
|
||||
<textPath
|
||||
:href="'#' + s.textPathId"
|
||||
startOffset="50%"
|
||||
text-anchor="middle"
|
||||
dominant-baseline="central"
|
||||
>
|
||||
{{ s.label }}
|
||||
</textPath>
|
||||
</text>
|
||||
<image
|
||||
v-else
|
||||
:href="s.svgPath"
|
||||
:x="getSectorSvgBox(s).x"
|
||||
:y="getSectorSvgBox(s).y"
|
||||
:width="getSectorSvgBox(s).size"
|
||||
:height="getSectorSvgBox(s).size"
|
||||
<template v-for="s in sectors" :key="'split-' + s.key">
|
||||
<line
|
||||
v-if="s.groupSplitVisible !== false"
|
||||
:x1="toXY(s.aStart, s.rInner).x"
|
||||
:y1="toXY(s.aStart, s.rInner).y"
|
||||
:x2="toXY(s.aStart, s.rOuter).x"
|
||||
:y2="toXY(s.aStart, s.rOuter).y"
|
||||
/>
|
||||
</template>
|
||||
</g>
|
||||
|
||||
</template>
|
||||
<!-- 形心点(仅辅助线开启时显示) -->
|
||||
<g v-if="showGuides" v-memo="[sectors]">
|
||||
<circle
|
||||
v-for="s in sectors"
|
||||
:key="s.key + '-center'"
|
||||
:cx="s.cx"
|
||||
:cy="s.cy"
|
||||
r="2.2"
|
||||
fill="#ef4444"
|
||||
opacity="0.8"
|
||||
/>
|
||||
</g>
|
||||
|
||||
<!-- 辅助线:圆环、分度线 -->
|
||||
<g v-if="showGuides" v-memo="[rings, anglesDeg, outerMost]" stroke="#111827" stroke-opacity="0.18">
|
||||
<!-- 圆环 -->
|
||||
<circle
|
||||
v-for="r in rings"
|
||||
:key="'ring-' + r"
|
||||
:r="r"
|
||||
fill="none"
|
||||
:stroke-width="SECTOR_STROKE_WIDTH"
|
||||
/>
|
||||
<!-- 径向线 -->
|
||||
<line
|
||||
v-for="a in anglesDeg"
|
||||
:key="'ang-' + a"
|
||||
:x1="0"
|
||||
:y1="0"
|
||||
:x2="toXY(a, outerMost).x"
|
||||
:y2="toXY(a, outerMost).y"
|
||||
:stroke-width="SECTOR_STROKE_WIDTH"
|
||||
/>
|
||||
</g>
|
||||
|
||||
<!-- 刻度环 -->
|
||||
<g v-if="degreeRing" v-memo="[degreeRing]">
|
||||
<defs>
|
||||
<path
|
||||
v-for="label in degreeRing.labels || []"
|
||||
:key="label.textPathId"
|
||||
:id="label.textPathId"
|
||||
:d="label.textPath"
|
||||
fill="none"
|
||||
/>
|
||||
</defs>
|
||||
<circle
|
||||
v-if="degreeRing.background"
|
||||
:r="(degreeRing.ring.rInner + degreeRing.ring.rOuter) / 2"
|
||||
fill="none"
|
||||
:stroke="degreeRing.background.color"
|
||||
:stroke-opacity="degreeRing.background.opacity"
|
||||
:stroke-width="degreeRing.ring.rOuter - degreeRing.ring.rInner"
|
||||
/>
|
||||
<circle
|
||||
:r="degreeRing.ring.rOuter"
|
||||
fill="none"
|
||||
:stroke="degreeRing.ring.color"
|
||||
:stroke-opacity="degreeRing.ring.opacity"
|
||||
:stroke-width="SECTOR_STROKE_WIDTH"
|
||||
/>
|
||||
<circle
|
||||
:r="degreeRing.ring.rInner"
|
||||
fill="none"
|
||||
:stroke="degreeRing.ring.color"
|
||||
:stroke-opacity="degreeRing.ring.opacity"
|
||||
:stroke-width="SECTOR_STROKE_WIDTH"
|
||||
/>
|
||||
<line
|
||||
v-for="tick in degreeRing.ticks"
|
||||
:key="'tick-' + tick.angle + '-' + tick.startR + '-' + tick.endR"
|
||||
:x1="tick.x1"
|
||||
:y1="tick.y1"
|
||||
:x2="tick.x2"
|
||||
:y2="tick.y2"
|
||||
:stroke="degreeRing.tickColor"
|
||||
:stroke-width="SECTOR_STROKE_WIDTH"
|
||||
/>
|
||||
<text
|
||||
v-for="label in degreeRing.labels || []"
|
||||
:key="'degree-' + label.angle"
|
||||
:fill="degreeRing.tickColor"
|
||||
:font-size="label.fontSize"
|
||||
style="user-select: none"
|
||||
>
|
||||
<textPath
|
||||
:href="'#' + label.textPathId"
|
||||
startOffset="50%"
|
||||
text-anchor="middle"
|
||||
dominant-baseline="central"
|
||||
>
|
||||
{{ label.text }}
|
||||
</textPath>
|
||||
</text>
|
||||
</g>
|
||||
|
||||
<!-- 中心图标 -->
|
||||
<g v-if="centerIcon" v-memo="[centerIcon]">
|
||||
<image
|
||||
:href="centerIcon.svgPath"
|
||||
:width="centerIcon.rIcon * 2"
|
||||
:height="centerIcon.rIcon * 2"
|
||||
:x="-centerIcon.rIcon"
|
||||
:y="-centerIcon.rIcon"
|
||||
:opacity="centerIcon.opacity"
|
||||
:transform="`rotate(${centerIcon.rotation})`"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
|
||||
<!-- 扇区边界线 -->
|
||||
<g
|
||||
v-memo="[sectors, boundaryRings, strokeColor, strokeOpacity, strokeWidth]"
|
||||
:stroke="strokeColor"
|
||||
:stroke-opacity="strokeOpacity"
|
||||
:stroke-width="strokeWidth"
|
||||
>
|
||||
<circle
|
||||
v-for="r in boundaryRings"
|
||||
:key="'ring-outline-' + r"
|
||||
:r="r"
|
||||
fill="none"
|
||||
/>
|
||||
<template v-for="s in sectors" :key="'split-' + s.key">
|
||||
<line
|
||||
v-if="s.groupSplitVisible !== false"
|
||||
:x1="toXY(s.aStart, s.rInner).x"
|
||||
:y1="toXY(s.aStart, s.rInner).y"
|
||||
:x2="toXY(s.aStart, s.rOuter).x"
|
||||
:y2="toXY(s.aStart, s.rOuter).y"
|
||||
/>
|
||||
</template>
|
||||
</g>
|
||||
|
||||
<!-- 形心点(仅辅助线开启时显示) -->
|
||||
<g v-if="showGuides" v-memo="[sectors]">
|
||||
<circle
|
||||
v-for="s in sectors"
|
||||
:key="s.key + '-center'"
|
||||
:cx="s.cx"
|
||||
:cy="s.cy"
|
||||
r="2.2"
|
||||
fill="#ef4444"
|
||||
opacity="0.8"
|
||||
/>
|
||||
</g>
|
||||
|
||||
<!-- 辅助线:圆环、分度线 -->
|
||||
<g v-if="showGuides" v-memo="[rings, anglesDeg, outerMost]" stroke="#111827" stroke-opacity="0.18">
|
||||
<!-- 圆环 -->
|
||||
<circle
|
||||
v-for="r in rings"
|
||||
:key="'ring-' + r"
|
||||
:r="r"
|
||||
fill="none"
|
||||
:stroke-width="SECTOR_STROKE_WIDTH"
|
||||
/>
|
||||
<!-- 径向线 -->
|
||||
<line
|
||||
v-for="a in anglesDeg"
|
||||
:key="'ang-' + a"
|
||||
:x1="0"
|
||||
:y1="0"
|
||||
:x2="toXY(a, outerMost).x"
|
||||
:y2="toXY(a, outerMost).y"
|
||||
:stroke-width="SECTOR_STROKE_WIDTH"
|
||||
/>
|
||||
</g>
|
||||
|
||||
<!-- 刻度环 -->
|
||||
<g v-if="degreeRing" v-memo="[degreeRing]">
|
||||
<defs>
|
||||
<path
|
||||
v-for="label in degreeRing.labels || []"
|
||||
:key="label.textPathId"
|
||||
:id="label.textPathId"
|
||||
:d="label.textPath"
|
||||
fill="none"
|
||||
/>
|
||||
</defs>
|
||||
<circle
|
||||
:r="degreeRing.ring.rOuter"
|
||||
fill="none"
|
||||
:stroke="degreeRing.ring.color"
|
||||
:stroke-opacity="degreeRing.ring.opacity"
|
||||
:stroke-width="SECTOR_STROKE_WIDTH"
|
||||
/>
|
||||
<circle
|
||||
:r="degreeRing.ring.rInner"
|
||||
fill="none"
|
||||
:stroke="degreeRing.ring.color"
|
||||
:stroke-opacity="degreeRing.ring.opacity"
|
||||
:stroke-width="SECTOR_STROKE_WIDTH"
|
||||
/>
|
||||
<line
|
||||
v-for="tick in degreeRing.ticks"
|
||||
:key="'tick-' + tick.angle + '-' + tick.startR + '-' + tick.endR"
|
||||
:x1="tick.x1"
|
||||
:y1="tick.y1"
|
||||
:x2="tick.x2"
|
||||
:y2="tick.y2"
|
||||
:stroke="degreeRing.tickColor"
|
||||
:stroke-width="SECTOR_STROKE_WIDTH"
|
||||
/>
|
||||
<text
|
||||
v-for="label in degreeRing.labels || []"
|
||||
:key="'degree-' + label.angle"
|
||||
:fill="degreeRing.tickColor"
|
||||
:font-size="label.fontSize"
|
||||
style="user-select: none"
|
||||
>
|
||||
<textPath
|
||||
:href="'#' + label.textPathId"
|
||||
startOffset="50%"
|
||||
text-anchor="middle"
|
||||
dominant-baseline="central"
|
||||
>
|
||||
{{ label.text }}
|
||||
</textPath>
|
||||
</text>
|
||||
</g>
|
||||
|
||||
<!-- 中心图标 -->
|
||||
<g v-if="centerIcon" v-memo="[centerIcon]">
|
||||
<image
|
||||
:href="centerIcon.svgPath"
|
||||
:width="centerIcon.rIcon * 2"
|
||||
:height="centerIcon.rIcon * 2"
|
||||
:x="-centerIcon.rIcon"
|
||||
:y="-centerIcon.rIcon"
|
||||
:opacity="centerIcon.opacity"
|
||||
:transform="`rotate(${centerIcon.rotation})`"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
@@ -341,6 +348,7 @@ const textRadialPosition = ref<TextRadialPosition>(DEFAULT_TEXT_RADIAL_POSITION)
|
||||
const scale = ref(1);
|
||||
const panX = ref(0);
|
||||
const panY = ref(0);
|
||||
const viewport = ref<SVGGElement | null>(null);
|
||||
let nextScale = scale.value;
|
||||
let nextPanX = panX.value;
|
||||
let nextPanY = panY.value;
|
||||
@@ -421,6 +429,9 @@ const loadConfigList = async () => {
|
||||
};
|
||||
|
||||
onMounted(loadConfigList);
|
||||
onMounted(() => {
|
||||
applyViewportTransform(scale.value, panX.value, panY.value);
|
||||
});
|
||||
|
||||
watch(selectedConfigPath, (value, previous) => {
|
||||
if (value === previous) return;
|
||||
@@ -472,6 +483,14 @@ const boundaryRings = computed(() => {
|
||||
return Array.from(set);
|
||||
});
|
||||
|
||||
const applyViewportTransform = (scaleValue: number, panXValue: number, panYValue: number) => {
|
||||
if (!viewport.value) return;
|
||||
viewport.value.setAttribute(
|
||||
'transform',
|
||||
`scale(${scaleValue}) translate(${panXValue}, ${panYValue})`
|
||||
);
|
||||
};
|
||||
|
||||
// 使用 `rAF` 合并缩放/拖拽更新,减少渲染频率
|
||||
const scheduleTransform = () => {
|
||||
if (rafId !== null) return;
|
||||
@@ -484,6 +503,7 @@ const scheduleTransform = () => {
|
||||
scale.value = nextScale;
|
||||
panX.value = nextPanX;
|
||||
panY.value = nextPanY;
|
||||
applyViewportTransform(nextScale, nextPanX, nextPanY);
|
||||
rafId = null;
|
||||
});
|
||||
};
|
||||
@@ -638,6 +658,12 @@ button.active {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
contain: paint;
|
||||
cursor: grab;
|
||||
}
|
||||
|
||||
.svg-container.is-dragging {
|
||||
cursor: grabbing;
|
||||
}
|
||||
|
||||
.status {
|
||||
@@ -650,10 +676,13 @@ button.active {
|
||||
|
||||
.svg {
|
||||
background: transparent;
|
||||
transition: transform 0.1s ease-out;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.viewport {
|
||||
will-change: transform;
|
||||
}
|
||||
|
||||
.note {
|
||||
color: #6b7280;
|
||||
font-size: 13px;
|
||||
|
||||
@@ -16,8 +16,8 @@ import type {
|
||||
ThemesConfig,
|
||||
TextRadialPosition,
|
||||
} from '../types';
|
||||
import { polarToXY } from '../utils';
|
||||
import { parseConfig } from '../configParser';
|
||||
import { getTextColorForBackground, polarToXY } from '../utils';
|
||||
import { normalizeLayerRadii, parseConfig } from '../configParser';
|
||||
import { ColorResolver } from '../colorResolver';
|
||||
import { SectorBuilder } from '../sectorBuilder';
|
||||
import { buildDegreeRing } from '../degreeRing';
|
||||
@@ -39,6 +39,29 @@ const resolveThemeColor = (
|
||||
return theme.colorPalettes[value] ?? fallback;
|
||||
};
|
||||
|
||||
const resolveDegreeRingColor = (
|
||||
value: string | undefined,
|
||||
theme: ThemeConfig,
|
||||
background: string
|
||||
) => {
|
||||
if (typeof value === 'string' && value.trim().length > 0) {
|
||||
return resolveThemeColor(theme, value, value);
|
||||
}
|
||||
const contrast = getTextColorForBackground(background);
|
||||
return contrast === '#ffffff' ? '#ffffff' : '#000000';
|
||||
};
|
||||
|
||||
const resolveDegreeRingBackground = (
|
||||
value: string | undefined,
|
||||
theme: ThemeConfig,
|
||||
fallback: string
|
||||
) => {
|
||||
if (typeof value === 'string' && value.trim().length > 0) {
|
||||
return resolveThemeColor(theme, value, fallback);
|
||||
}
|
||||
return fallback;
|
||||
};
|
||||
|
||||
const findDegreeRingLayer = (layers: LayerConfig[]) =>
|
||||
layers.find((layer) => layer.type === 'degreeRing');
|
||||
|
||||
@@ -158,39 +181,45 @@ export function useLuopan(
|
||||
error.value = null;
|
||||
|
||||
let configObj: LuopanConfigInput;
|
||||
let normalizedLayers: LuopanConfig['layers'];
|
||||
const configInput = configSource.value;
|
||||
if (typeof configInput === 'string') {
|
||||
const jsonText = await fetch(configInput).then((res) => res.text());
|
||||
configObj = parseConfig(jsonText);
|
||||
// parseConfig 已完成层归一化,避免重复处理
|
||||
normalizedLayers = configObj.layers;
|
||||
} else {
|
||||
configObj = configInput;
|
||||
normalizedLayers = normalizeLayerRadii(configObj.layers);
|
||||
}
|
||||
|
||||
const resolvedTheme = await resolveTheme(configObj);
|
||||
const normalizedConfig = { ...configObj, layers: normalizedLayers };
|
||||
|
||||
const resolvedTheme = await resolveTheme(normalizedConfig);
|
||||
const resolvedBackground = resolveThemeColor(
|
||||
resolvedTheme,
|
||||
configObj.background,
|
||||
normalizedConfig.background,
|
||||
'#000000'
|
||||
);
|
||||
const resolvedStrokeColor = resolveThemeColor(
|
||||
resolvedTheme,
|
||||
configObj.strokeColor,
|
||||
normalizedConfig.strokeColor,
|
||||
'#1f2937'
|
||||
);
|
||||
|
||||
const resolvedConfig: LuopanConfig = {
|
||||
...configObj,
|
||||
...normalizedConfig,
|
||||
theme: resolvedTheme,
|
||||
background: resolvedBackground,
|
||||
strokeColor: resolvedStrokeColor,
|
||||
strokeWidth: typeof configObj.strokeWidth === 'number'
|
||||
? configObj.strokeWidth
|
||||
strokeWidth: typeof normalizedConfig.strokeWidth === 'number'
|
||||
? normalizedConfig.strokeWidth
|
||||
: undefined,
|
||||
strokeOpacity: typeof configObj.strokeOpacity === 'number'
|
||||
? configObj.strokeOpacity
|
||||
strokeOpacity: typeof normalizedConfig.strokeOpacity === 'number'
|
||||
? normalizedConfig.strokeOpacity
|
||||
: undefined,
|
||||
insetDistance: typeof configObj.insetDistance === 'number'
|
||||
? configObj.insetDistance
|
||||
insetDistance: typeof normalizedConfig.insetDistance === 'number'
|
||||
? normalizedConfig.insetDistance
|
||||
: undefined,
|
||||
};
|
||||
|
||||
@@ -198,15 +227,52 @@ export function useLuopan(
|
||||
sectors.value = buildSectors(resolvedConfig);
|
||||
|
||||
const degreeRingLayer = findDegreeRingLayer(resolvedConfig.layers);
|
||||
degreeRing.value = degreeRingLayer
|
||||
? buildDegreeRing(degreeRingLayer.degreeRing)
|
||||
: null;
|
||||
if (degreeRingLayer) {
|
||||
const ringBackground = resolveDegreeRingBackground(
|
||||
degreeRingLayer.degreeRing.colorRef,
|
||||
resolvedConfig.theme,
|
||||
resolvedConfig.background
|
||||
);
|
||||
const hasBackgroundRef =
|
||||
typeof degreeRingLayer.degreeRing.colorRef === 'string' &&
|
||||
degreeRingLayer.degreeRing.colorRef.trim().length > 0;
|
||||
const tickColor = resolveDegreeRingColor(
|
||||
degreeRingLayer.degreeRing.tickColor,
|
||||
resolvedConfig.theme,
|
||||
ringBackground
|
||||
);
|
||||
const ringColor = resolveDegreeRingColor(
|
||||
degreeRingLayer.degreeRing.ringColor,
|
||||
resolvedConfig.theme,
|
||||
ringBackground
|
||||
);
|
||||
const ringData = buildDegreeRing({
|
||||
...degreeRingLayer.degreeRing,
|
||||
tickColor,
|
||||
ringColor,
|
||||
});
|
||||
degreeRing.value = {
|
||||
...ringData,
|
||||
background: hasBackgroundRef
|
||||
? {
|
||||
color: ringBackground,
|
||||
opacity: degreeRingLayer.degreeRing.opacity,
|
||||
}
|
||||
: undefined,
|
||||
};
|
||||
} else {
|
||||
degreeRing.value = null;
|
||||
}
|
||||
|
||||
const centerIconLayer = findCenterIconLayer(resolvedConfig.layers);
|
||||
centerIcon.value = centerIconLayer
|
||||
? await loadCenterIcon(centerIconLayer.centerIcon)
|
||||
: null;
|
||||
} catch (err) {
|
||||
console.error('加载罗盘配置失败', {
|
||||
source: typeof configSource.value === 'string' ? configSource.value : 'inline config',
|
||||
error: err,
|
||||
});
|
||||
error.value = err as Error;
|
||||
} finally {
|
||||
loading.value = false;
|
||||
|
||||
@@ -1,4 +1,13 @@
|
||||
import type { LuopanConfigInput, ThemeConfig } from './types';
|
||||
import type {
|
||||
DegreeRingLayerConfig,
|
||||
DegreeRingLayerConfigInput,
|
||||
LayerConfig,
|
||||
LayerConfigInput,
|
||||
LuopanConfigInput,
|
||||
SectorLayerConfig,
|
||||
SectorLayerConfigInput,
|
||||
ThemeConfig,
|
||||
} from './types';
|
||||
|
||||
const isObject = (value: unknown): value is Record<string, unknown> =>
|
||||
typeof value === 'object' && value !== null && !Array.isArray(value);
|
||||
@@ -9,6 +18,9 @@ const assertCondition = (condition: boolean, message: string): void => {
|
||||
}
|
||||
};
|
||||
|
||||
const isFiniteNumber = (value: unknown): value is number =>
|
||||
typeof value === 'number' && Number.isFinite(value);
|
||||
|
||||
export const stripJsonComments = (input: string): string => {
|
||||
let output = '';
|
||||
let inString = false;
|
||||
@@ -53,6 +65,175 @@ const normalizeTheme = (theme: Record<string, unknown>): ThemeConfig => {
|
||||
};
|
||||
};
|
||||
|
||||
const normalizeSectorLayer = (
|
||||
layer: SectorLayerConfigInput,
|
||||
index: number,
|
||||
lastOuter: number | null
|
||||
): { layer: SectorLayerConfig; nextOuter: number } => {
|
||||
const rInnerRaw = layer.rInner;
|
||||
const rOuterRaw = layer.rOuter;
|
||||
const layerHeightRaw = layer.layerHeight;
|
||||
|
||||
const hasRInner = rInnerRaw !== undefined;
|
||||
const hasROuter = rOuterRaw !== undefined;
|
||||
|
||||
if (hasRInner && !isFiniteNumber(rInnerRaw)) {
|
||||
throw new Error(`layers[${index}].rInner 必须为数字`);
|
||||
}
|
||||
if (hasROuter && !isFiniteNumber(rOuterRaw)) {
|
||||
throw new Error(`layers[${index}].rOuter 必须为数字`);
|
||||
}
|
||||
|
||||
if (hasRInner || hasROuter) {
|
||||
assertCondition(
|
||||
hasRInner && hasROuter,
|
||||
`layers[${index}] 必须同时提供 rInner 与 rOuter`
|
||||
);
|
||||
const rInner = rInnerRaw as number;
|
||||
const rOuter = rOuterRaw as number;
|
||||
assertCondition(rOuter > rInner, `layers[${index}] rOuter 必须大于 rInner`);
|
||||
return {
|
||||
layer: { ...layer, rInner, rOuter },
|
||||
nextOuter: rOuter,
|
||||
};
|
||||
}
|
||||
|
||||
if (layerHeightRaw === undefined) {
|
||||
throw new Error(`layers[${index}] 缺少 rInner/rOuter 或 layerHeight`);
|
||||
}
|
||||
if (!isFiniteNumber(layerHeightRaw)) {
|
||||
throw new Error(`layers[${index}].layerHeight 必须为数字`);
|
||||
}
|
||||
assertCondition(
|
||||
layerHeightRaw > 0,
|
||||
`layers[${index}].layerHeight 必须大于 0`
|
||||
);
|
||||
assertCondition(
|
||||
lastOuter !== null,
|
||||
`layers[${index}] 使用 layerHeight 时必须有上一层 rOuter`
|
||||
);
|
||||
|
||||
const rInner = lastOuter as number;
|
||||
const rOuter = rInner + layerHeightRaw;
|
||||
return {
|
||||
layer: { ...layer, rInner, rOuter },
|
||||
nextOuter: rOuter,
|
||||
};
|
||||
};
|
||||
|
||||
const normalizeDegreeRingLayer = (
|
||||
layer: DegreeRingLayerConfigInput,
|
||||
index: number,
|
||||
lastOuter: number | null
|
||||
): { layer: DegreeRingLayerConfig; nextOuter: number } => {
|
||||
if (Object.prototype.hasOwnProperty.call(layer, 'degreeRing')) {
|
||||
const keys = Object.keys(layer).join(', ');
|
||||
console.error('检测到废弃的 degreeRing 嵌套配置', {
|
||||
index,
|
||||
keys,
|
||||
layer,
|
||||
});
|
||||
throw new Error(
|
||||
`layers[${index}].degreeRing 已废弃,请改为扁平写法(keys: ${keys})`
|
||||
);
|
||||
}
|
||||
const { type: _type, layerHeight: layerHeightRaw, ...degreeRing } = layer;
|
||||
|
||||
const rInnerRaw = degreeRing.rInner;
|
||||
const rOuterRaw = degreeRing.rOuter;
|
||||
|
||||
const hasRInner = rInnerRaw !== undefined;
|
||||
const hasROuter = rOuterRaw !== undefined;
|
||||
|
||||
if (hasRInner && !isFiniteNumber(rInnerRaw)) {
|
||||
throw new Error(`layers[${index}].rInner 必须为数字`);
|
||||
}
|
||||
if (hasROuter && !isFiniteNumber(rOuterRaw)) {
|
||||
throw new Error(`layers[${index}].rOuter 必须为数字`);
|
||||
}
|
||||
|
||||
if (hasRInner || hasROuter) {
|
||||
assertCondition(
|
||||
hasRInner && hasROuter,
|
||||
`layers[${index}] 必须同时提供 rInner 与 rOuter`
|
||||
);
|
||||
const rInner = rInnerRaw as number;
|
||||
const rOuter = rOuterRaw as number;
|
||||
assertCondition(
|
||||
rOuter > rInner,
|
||||
`layers[${index}].rOuter 必须大于 rInner`
|
||||
);
|
||||
return {
|
||||
layer: {
|
||||
type: 'degreeRing',
|
||||
layerHeight: layerHeightRaw,
|
||||
degreeRing: { ...degreeRing, rInner, rOuter },
|
||||
},
|
||||
nextOuter: rOuter,
|
||||
};
|
||||
}
|
||||
|
||||
if (layerHeightRaw === undefined) {
|
||||
throw new Error(`layers[${index}] 缺少 rInner/rOuter 或 layerHeight`);
|
||||
}
|
||||
if (!isFiniteNumber(layerHeightRaw)) {
|
||||
throw new Error(`layers[${index}].layerHeight 必须为数字`);
|
||||
}
|
||||
assertCondition(
|
||||
layerHeightRaw > 0,
|
||||
`layers[${index}].layerHeight 必须大于 0`
|
||||
);
|
||||
assertCondition(
|
||||
lastOuter !== null,
|
||||
`layers[${index}] 使用 layerHeight 时必须有上一层 rOuter`
|
||||
);
|
||||
|
||||
const rInner = lastOuter as number;
|
||||
const rOuter = rInner + layerHeightRaw;
|
||||
return {
|
||||
layer: {
|
||||
type: 'degreeRing',
|
||||
layerHeight: layerHeightRaw,
|
||||
degreeRing: { ...degreeRing, rInner, rOuter },
|
||||
},
|
||||
nextOuter: rOuter,
|
||||
};
|
||||
};
|
||||
|
||||
export const normalizeLayerRadii = (layers: LayerConfigInput[]): LayerConfig[] => {
|
||||
const normalized: LayerConfig[] = [];
|
||||
let lastOuter: number | null = null;
|
||||
|
||||
layers.forEach((layer, index) => {
|
||||
assertCondition(isObject(layer), `layers[${index}] 必须为对象`);
|
||||
const type = (layer as Record<string, unknown>).type;
|
||||
if (type === 'centerIcon') {
|
||||
normalized.push(layer as LayerConfig);
|
||||
return;
|
||||
}
|
||||
if (type === 'degreeRing') {
|
||||
const { layer: degreeRingLayer, nextOuter } = normalizeDegreeRingLayer(
|
||||
layer as DegreeRingLayerConfigInput,
|
||||
index,
|
||||
lastOuter
|
||||
);
|
||||
normalized.push(degreeRingLayer);
|
||||
lastOuter = nextOuter;
|
||||
return;
|
||||
}
|
||||
|
||||
const { layer: sectorLayer, nextOuter } = normalizeSectorLayer(
|
||||
layer as SectorLayerConfigInput,
|
||||
index,
|
||||
lastOuter
|
||||
);
|
||||
normalized.push(sectorLayer);
|
||||
lastOuter = nextOuter;
|
||||
});
|
||||
|
||||
return normalized;
|
||||
};
|
||||
|
||||
export const parseConfig = (jsonText: string): LuopanConfigInput => {
|
||||
const cleanText = stripJsonComments(jsonText);
|
||||
let parsed: unknown;
|
||||
@@ -73,6 +254,7 @@ export const parseConfig = (jsonText: string): LuopanConfigInput => {
|
||||
assertCondition(isObject(config.theme), 'theme 必须为对象');
|
||||
}
|
||||
assertCondition(Array.isArray(config.layers), 'layers 为必填数组');
|
||||
const normalizedLayers = normalizeLayerRadii(config.layers as LayerConfigInput[]);
|
||||
|
||||
return {
|
||||
name: config.name,
|
||||
@@ -85,6 +267,6 @@ export const parseConfig = (jsonText: string): LuopanConfigInput => {
|
||||
outerRadius: typeof config.outerRadius === 'number' ? config.outerRadius : undefined,
|
||||
themeRef: typeof config.themeRef === 'string' ? config.themeRef : undefined,
|
||||
theme: isObject(config.theme) ? normalizeTheme(config.theme) : undefined,
|
||||
layers: config.layers as LuopanConfigInput['layers'],
|
||||
layers: normalizedLayers,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -15,6 +15,8 @@ export function buildDegreeRing(config: DegreeRingConfig): DegreeRingData {
|
||||
const ticks: TickMark[] = [];
|
||||
const { rInner, rOuter, mode } = config;
|
||||
const labelFontSize = 8;
|
||||
const tickColor = config.tickColor ?? '#000000';
|
||||
const ringColor = config.ringColor ?? tickColor;
|
||||
|
||||
const majorTick = Math.max(1, config.majorTick);
|
||||
const minorTick = Math.max(1, config.minorTick);
|
||||
@@ -125,11 +127,11 @@ export function buildDegreeRing(config: DegreeRingConfig): DegreeRingData {
|
||||
|
||||
return {
|
||||
ticks,
|
||||
tickColor: config.tickColor,
|
||||
tickColor,
|
||||
ring: {
|
||||
rInner,
|
||||
rOuter,
|
||||
color: config.ringColor,
|
||||
color: ringColor,
|
||||
opacity: config.opacity,
|
||||
},
|
||||
labels: labels.length > 0 ? labels : undefined,
|
||||
|
||||
@@ -62,10 +62,6 @@ export class SectorBuilder {
|
||||
|
||||
// 颜色优先级:扇区 > 规律填色 > 背景
|
||||
const fillColor = this.colorResolver.resolveSectorColor(layerColorMap, sectorConfig, i);
|
||||
const layerColor = layer.colorRef ? this.colorResolver.resolveColor(layer.colorRef) : undefined;
|
||||
const sectorColor = sectorConfig?.colorRef
|
||||
? this.colorResolver.resolveColor(sectorConfig.colorRef)
|
||||
: undefined;
|
||||
// 扇区的 `innerFill` 优先级高于层级的 `innerFill`。
|
||||
const innerFill = (sectorConfig?.innerFill ?? layer.innerFill ?? 0) === 1;
|
||||
const innerFillPath = innerFill
|
||||
@@ -80,10 +76,10 @@ export class SectorBuilder {
|
||||
const normalizedInnerFillPath =
|
||||
innerFillPath && innerFillPath.length > 0 ? innerFillPath : undefined;
|
||||
const hasInnerFillPath = Boolean(normalizedInnerFillPath);
|
||||
// `innerFill` 开启时:外圈保持白色,仅填充内缩块。
|
||||
// `innerFill` 开启时:外圈保持白色,内缩块仍按规律填色。
|
||||
const baseFillColor = hasInnerFillPath ? '#ffffff' : fillColor;
|
||||
const innerFillColor = hasInnerFillPath ? sectorColor ?? layerColor ?? fillColor : undefined;
|
||||
const textBaseColor = hasInnerFillPath ? innerFillColor ?? fillColor : fillColor;
|
||||
const innerFillColor = hasInnerFillPath ? fillColor : undefined;
|
||||
const textBaseColor = fillColor;
|
||||
const textColor = getTextColorForBackground(textBaseColor);
|
||||
|
||||
const sectorKey = `L${layerIndex}-P${i}`;
|
||||
|
||||
50
src/types.ts
50
src/types.ts
@@ -22,7 +22,7 @@ export interface Example {
|
||||
/**
|
||||
* JSON 配置根对象
|
||||
*/
|
||||
export interface LuopanConfigBase {
|
||||
export interface LuopanConfigBase<TLayer = LayerConfig> {
|
||||
name: string;
|
||||
description?: string;
|
||||
background: string;
|
||||
@@ -33,15 +33,13 @@ export interface LuopanConfigBase {
|
||||
outerRadius?: number;
|
||||
themeRef?: string;
|
||||
theme?: ThemeConfig;
|
||||
layers: LayerConfig[];
|
||||
layers: TLayer[];
|
||||
}
|
||||
|
||||
export interface LuopanConfig extends LuopanConfigBase {
|
||||
export interface LuopanConfig extends LuopanConfigBase<LayerConfig> {
|
||||
theme: ThemeConfig;
|
||||
}
|
||||
|
||||
export type LuopanConfigInput = LuopanConfigBase;
|
||||
|
||||
/**
|
||||
* 主题配置
|
||||
*/
|
||||
@@ -84,8 +82,15 @@ export interface DegreeRingConfig {
|
||||
majorTick: number;
|
||||
minorTick: number;
|
||||
microTick: number;
|
||||
tickColor: string;
|
||||
ringColor: string;
|
||||
tickColor?: string;
|
||||
ringColor?: string;
|
||||
colorRef?: string;
|
||||
}
|
||||
|
||||
export interface DegreeRingConfigInput
|
||||
extends Omit<DegreeRingConfig, 'rInner' | 'rOuter'> {
|
||||
rInner?: number;
|
||||
rOuter?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -99,11 +104,9 @@ export type LayerConfig =
|
||||
/**
|
||||
* 普通扇区层配置
|
||||
*/
|
||||
export interface SectorLayerConfig {
|
||||
interface SectorLayerBase {
|
||||
type?: 'sectors';
|
||||
divisions: number;
|
||||
rInner: number;
|
||||
rOuter: number;
|
||||
startAngle?: number;
|
||||
colorRef?: string;
|
||||
innerFill?: 0 | 1;
|
||||
@@ -115,6 +118,25 @@ export interface SectorLayerConfig {
|
||||
sectors?: SectorConfig[];
|
||||
}
|
||||
|
||||
export interface SectorLayerConfig extends SectorLayerBase {
|
||||
rInner: number;
|
||||
rOuter: number;
|
||||
layerHeight?: number;
|
||||
}
|
||||
|
||||
export interface SectorLayerConfigInput extends SectorLayerBase {
|
||||
rInner?: number;
|
||||
rOuter?: number;
|
||||
layerHeight?: number;
|
||||
}
|
||||
|
||||
export type LayerConfigInput =
|
||||
| SectorLayerConfigInput
|
||||
| CenterIconLayerConfig
|
||||
| DegreeRingLayerConfigInput;
|
||||
|
||||
export type LuopanConfigInput = LuopanConfigBase<LayerConfigInput>;
|
||||
|
||||
/**
|
||||
* 中心图标层配置
|
||||
*/
|
||||
@@ -129,6 +151,13 @@ export interface CenterIconLayerConfig {
|
||||
export interface DegreeRingLayerConfig {
|
||||
type: 'degreeRing';
|
||||
degreeRing: DegreeRingConfig;
|
||||
layerHeight?: number;
|
||||
}
|
||||
|
||||
// 扁平化输入:刻度环字段直接挂在层上。
|
||||
export interface DegreeRingLayerConfigInput extends DegreeRingConfigInput {
|
||||
type: 'degreeRing';
|
||||
layerHeight?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -190,6 +219,7 @@ export interface DegreeRingData {
|
||||
ticks: TickMark[];
|
||||
tickColor: string;
|
||||
ring: { rInner: number; rOuter: number; color: string; opacity: number };
|
||||
background?: { color: string; opacity: number };
|
||||
labels?: DegreeLabel[];
|
||||
}
|
||||
|
||||
|
||||
@@ -5,11 +5,11 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { mount } from '@vue/test-utils';
|
||||
import Luopan from '../src/Luopan.vue';
|
||||
import type { LuopanConfig } from '../src/types';
|
||||
import type { LuopanConfigInput } from '../src/types';
|
||||
|
||||
const flushPromises = () => new Promise((resolve) => setTimeout(resolve, 0));
|
||||
|
||||
const baseConfig: LuopanConfig = {
|
||||
const baseConfig: LuopanConfigInput = {
|
||||
name: '测试配置',
|
||||
background: '#000000',
|
||||
theme: {
|
||||
@@ -26,20 +26,18 @@ const baseConfig: LuopanConfig = {
|
||||
},
|
||||
{
|
||||
type: 'degreeRing',
|
||||
degreeRing: {
|
||||
rInner: 90,
|
||||
rOuter: 100,
|
||||
showDegree: 1,
|
||||
mode: 'both',
|
||||
opacity: 0.3,
|
||||
tickLength: 6,
|
||||
tickLengthStep: 1,
|
||||
majorTick: 10,
|
||||
minorTick: 5,
|
||||
microTick: 1,
|
||||
tickColor: '#ffffff',
|
||||
ringColor: '#ffffff',
|
||||
},
|
||||
rInner: 90,
|
||||
rOuter: 100,
|
||||
showDegree: 1,
|
||||
mode: 'both',
|
||||
opacity: 0.3,
|
||||
tickLength: 6,
|
||||
tickLengthStep: 1,
|
||||
majorTick: 10,
|
||||
minorTick: 5,
|
||||
microTick: 1,
|
||||
tickColor: '#ffffff',
|
||||
ringColor: '#ffffff',
|
||||
},
|
||||
{
|
||||
type: 'centerIcon',
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { ref } from 'vue';
|
||||
import { useLuopan } from '../src/composables/useLuopan';
|
||||
import type { LuopanConfig, TextRadialPosition } from '../src/types';
|
||||
import type { LuopanConfigInput, TextRadialPosition } from '../src/types';
|
||||
|
||||
const createMockConfig = (): LuopanConfig => ({
|
||||
const createMockConfig = (): LuopanConfigInput => ({
|
||||
name: '测试配置',
|
||||
background: '#000000',
|
||||
theme: {
|
||||
|
||||
Reference in New Issue
Block a user