@@ -35,6 +35,13 @@ function getClefFromNode(node: SNLayoutNode): SNVoiceMetaClef {
3535/**
3636 * 绘制升降号符号
3737 *
38+ * 使用 Unicode 字符显示变音记号,确保符合标准并兼容更多系统:
39+ * - 升号(♯):U+266F
40+ * - 降号(♭):U+266D
41+ * - 还原号(♮):U+266E
42+ * - 重升号(𝄪):U+1D12A
43+ * - 重降号(𝄫):U+1D12B
44+ *
3845 * @param parent - 父 SVG 元素
3946 * @param accidental - 变音记号类型
4047 * @param x - 升降号的 x 坐标(通常位于符头左侧)
@@ -46,158 +53,75 @@ function renderAccidental(
4653 x : number ,
4754 y : number ,
4855) : void {
49- const strokeWidth = 1.5 ;
50-
56+ // 使用 Unicode 字符显示,字体大小根据音符大小调整
57+ const baseFontSize = 12 ; // 基础字体大小
58+ const text = document . createElementNS ( 'http://www.w3.org/2000/svg' , 'text' ) ;
59+
60+ // 设置文本属性
61+ text . setAttribute ( 'x' , String ( x ) ) ;
62+ text . setAttribute ( 'y' , String ( y ) ) ;
63+ text . setAttribute ( 'font-family' , 'Arial, "DejaVu Sans", sans-serif' ) ; // 使用常见字体以确保兼容性
64+ text . setAttribute ( 'fill' , '#000' ) ;
65+ text . setAttribute ( 'text-anchor' , 'middle' ) ;
66+ text . setAttribute ( 'dominant-baseline' , 'central' ) ; // 垂直居中对齐
67+ text . setAttribute ( 'style' , 'font-weight: bold;' ) ; // 所有符号都加粗
68+
69+ // 根据变音记号类型设置对应的 Unicode 字符和字体大小
5170 switch ( accidental ) {
5271 case SNAccidental . SHARP : {
53- // 绘制升号(♯):两条垂直的平行线,中间有两条斜线
54- // 升号宽度约为 4-5px,高度约为 8px
55- const width = 4 ;
56- const height = 8 ;
57- const centerX = x - width / 2 ;
58- const centerY = y ;
59-
60- // 两条垂直的平行线
61- const line1 = document . createElementNS (
62- 'http://www.w3.org/2000/svg' ,
63- 'line' ,
64- ) ;
65- line1 . setAttribute ( 'x1' , String ( centerX ) ) ;
66- line1 . setAttribute ( 'y1' , String ( centerY - height / 2 ) ) ;
67- line1 . setAttribute ( 'x2' , String ( centerX ) ) ;
68- line1 . setAttribute ( 'y2' , String ( centerY + height / 2 ) ) ;
69- line1 . setAttribute ( 'stroke' , '#000' ) ;
70- line1 . setAttribute ( 'stroke-width' , String ( strokeWidth ) ) ;
71- parent . appendChild ( line1 ) ;
72-
73- const line2 = document . createElementNS (
74- 'http://www.w3.org/2000/svg' ,
75- 'line' ,
76- ) ;
77- line2 . setAttribute ( 'x1' , String ( centerX + width ) ) ;
78- line2 . setAttribute ( 'y1' , String ( centerY - height / 2 ) ) ;
79- line2 . setAttribute ( 'x2' , String ( centerX + width ) ) ;
80- line2 . setAttribute ( 'y2' , String ( centerY + height / 2 ) ) ;
81- line2 . setAttribute ( 'stroke' , '#000' ) ;
82- line2 . setAttribute ( 'stroke-width' , String ( strokeWidth ) ) ;
83- parent . appendChild ( line2 ) ;
84-
85- // 两条斜线(从左上到右下)
86- const slash1 = document . createElementNS (
87- 'http://www.w3.org/2000/svg' ,
88- 'line' ,
89- ) ;
90- slash1 . setAttribute ( 'x1' , String ( centerX - 1 ) ) ;
91- slash1 . setAttribute ( 'y1' , String ( centerY - height / 2 + 1 ) ) ;
92- slash1 . setAttribute ( 'x2' , String ( centerX + width + 1 ) ) ;
93- slash1 . setAttribute ( 'y2' , String ( centerY - height / 2 + 3 ) ) ;
94- slash1 . setAttribute ( 'stroke' , '#000' ) ;
95- slash1 . setAttribute ( 'stroke-width' , String ( strokeWidth ) ) ;
96- parent . appendChild ( slash1 ) ;
97-
98- const slash2 = document . createElementNS (
99- 'http://www.w3.org/2000/svg' ,
100- 'line' ,
101- ) ;
102- slash2 . setAttribute ( 'x1' , String ( centerX - 1 ) ) ;
103- slash2 . setAttribute ( 'y1' , String ( centerY + height / 2 - 3 ) ) ;
104- slash2 . setAttribute ( 'x2' , String ( centerX + width + 1 ) ) ;
105- slash2 . setAttribute ( 'y2' , String ( centerY + height / 2 - 1 ) ) ;
106- slash2 . setAttribute ( 'stroke' , '#000' ) ;
107- slash2 . setAttribute ( 'stroke-width' , String ( strokeWidth ) ) ;
108- parent . appendChild ( slash2 ) ;
72+ // 升号(♯):U+266F
73+ text . setAttribute ( 'font-size' , String ( baseFontSize ) ) ;
74+ text . textContent = '\u266F' ;
10975 break ;
11076 }
11177
11278 case SNAccidental . FLAT : {
113- // 绘制降号(♭):一个类似小写字母 b 的形状
114- const width = 3 ;
115- const height = 8 ;
116- const centerX = x ;
117- const centerY = y ;
118-
119- // 使用路径绘制降号
120- const path = document . createElementNS (
121- 'http://www.w3.org/2000/svg' ,
122- 'path' ,
123- ) ;
124- // 降号路径:从顶部开始,向下画一条曲线,然后向右上方弯曲
125- const pathData = `M ${ centerX } ${ centerY - height / 2 }
126- Q ${ centerX - width } ${ centerY - height / 4 } ${ centerX - width } ${ centerY }
127- Q ${ centerX - width } ${ centerY + height / 4 } ${ centerX } ${ centerY + height / 2 } ` ;
128- path . setAttribute ( 'd' , pathData ) ;
129- path . setAttribute ( 'fill' , 'none' ) ;
130- path . setAttribute ( 'stroke' , '#000' ) ;
131- path . setAttribute ( 'stroke-width' , String ( strokeWidth ) ) ;
132- path . setAttribute ( 'stroke-linecap' , 'round' ) ;
133- parent . appendChild ( path ) ;
79+ // 降号(♭):U+266D
80+ text . setAttribute ( 'font-size' , String ( baseFontSize ) ) ;
81+ text . textContent = '\u266D' ;
13482 break ;
13583 }
13684
13785 case SNAccidental . NATURAL : {
138- // 绘制还原号(♮):类似一个倾斜的矩形,中间有一条斜线
139- const width = 4 ;
140- const height = 8 ;
141- const centerX = x - width / 2 ;
142- const centerY = y ;
143-
144- // 左侧垂直线
145- const leftLine = document . createElementNS (
146- 'http://www.w3.org/2000/svg' ,
147- 'line' ,
148- ) ;
149- leftLine . setAttribute ( 'x1' , String ( centerX ) ) ;
150- leftLine . setAttribute ( 'y1' , String ( centerY - height / 2 + 1 ) ) ;
151- leftLine . setAttribute ( 'x2' , String ( centerX ) ) ;
152- leftLine . setAttribute ( 'y2' , String ( centerY + height / 2 ) ) ;
153- leftLine . setAttribute ( 'stroke' , '#000' ) ;
154- leftLine . setAttribute ( 'stroke-width' , String ( strokeWidth ) ) ;
155- parent . appendChild ( leftLine ) ;
156-
157- // 右侧垂直线
158- const rightLine = document . createElementNS (
159- 'http://www.w3.org/2000/svg' ,
160- 'line' ,
161- ) ;
162- rightLine . setAttribute ( 'x1' , String ( centerX + width ) ) ;
163- rightLine . setAttribute ( 'y1' , String ( centerY - height / 2 ) ) ;
164- rightLine . setAttribute ( 'x2' , String ( centerX + width ) ) ;
165- rightLine . setAttribute ( 'y2' , String ( centerY + height / 2 - 1 ) ) ;
166- rightLine . setAttribute ( 'stroke' , '#000' ) ;
167- rightLine . setAttribute ( 'stroke-width' , String ( strokeWidth ) ) ;
168- parent . appendChild ( rightLine ) ;
169-
170- // 中间的斜线(从左上到右下)
171- const middleLine = document . createElementNS (
172- 'http://www.w3.org/2000/svg' ,
173- 'line' ,
174- ) ;
175- middleLine . setAttribute ( 'x1' , String ( centerX ) ) ;
176- middleLine . setAttribute ( 'y1' , String ( centerY - height / 4 ) ) ;
177- middleLine . setAttribute ( 'x2' , String ( centerX + width ) ) ;
178- middleLine . setAttribute ( 'y2' , String ( centerY + height / 4 ) ) ;
179- middleLine . setAttribute ( 'stroke' , '#000' ) ;
180- middleLine . setAttribute ( 'stroke-width' , String ( strokeWidth ) ) ;
181- parent . appendChild ( middleLine ) ;
86+ // 还原号(♮):U+266E
87+ text . setAttribute ( 'font-size' , String ( baseFontSize ) ) ;
88+ text . textContent = '\u266E' ;
18289 break ;
18390 }
18491
18592 case SNAccidental . DOUBLE_SHARP : {
186- // 绘制重升号(×):两个升号叠加,稍微错开
187- const offset = 1.5 ;
188- renderAccidental ( parent , SNAccidental . SHARP , x - offset , y ) ;
189- renderAccidental ( parent , SNAccidental . SHARP , x + offset , y ) ;
93+ // 重升号(𝄪):U+1D12A
94+ const doubleSharpFontSize = baseFontSize * 2 ;
95+ text . setAttribute ( 'font-size' , String ( doubleSharpFontSize ) ) ;
96+ text . setAttribute ( 'dy' , '5' ) ;
97+ // 使用 String.fromCodePoint 来支持辅助平面字符
98+ try {
99+ text . textContent = String . fromCodePoint ( 0x1d12a ) ;
100+ } catch {
101+ // 如果系统不支持,则使用两个升号叠加
102+ text . textContent = '\u266F\u266F' ;
103+ text . setAttribute ( 'dx' , '-2' ) ; // 稍微调整位置
104+ }
190105 break ;
191106 }
192107
193108 case SNAccidental . DOUBLE_FLAT : {
194- // 绘制重降号(♭♭):两个降号并排
195- const offset = 2 ;
196- renderAccidental ( parent , SNAccidental . FLAT , x - offset , y ) ;
197- renderAccidental ( parent , SNAccidental . FLAT , x + offset , y ) ;
109+ // 重降号(𝄫):U+1D12B
110+ const doubleFlatFontSize = baseFontSize ;
111+ text . setAttribute ( 'font-size' , String ( doubleFlatFontSize ) ) ;
112+ // 使用 String.fromCodePoint 来支持辅助平面字符
113+ try {
114+ text . textContent = String . fromCodePoint ( 0x1d12b ) ;
115+ } catch {
116+ // 如果系统不支持,则使用两个降号并排
117+ text . textContent = '\u266D\u266D' ;
118+ text . setAttribute ( 'dx' , '-2' ) ; // 稍微调整位置
119+ }
198120 break ;
199121 }
200122 }
123+
124+ parent . appendChild ( text ) ;
201125}
202126
203127/**
0 commit comments