text-guitar-chart 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +18 -0
- package/FORMAT.md +277 -0
- package/LICENSE +21 -0
- package/README.md +41 -0
- package/docs/app.js +172 -0
- package/docs/bundle.js +8712 -0
- package/docs/bundle.js.map +7 -0
- package/docs/index.html +93 -0
- package/index.js +7 -0
- package/lib/editableSVGuitar.js +1050 -0
- package/lib/fingeringToString.js +261 -0
- package/lib/layoutChordStrings.js +92 -0
- package/lib/splitStringInRectangles.js +132 -0
- package/lib/stringToFingering.js +435 -0
- package/package.json +43 -0
- package/scripts/build.js +30 -0
- package/test/editableSVGuitar.test.js +444 -0
- package/test/fingeringToString.test.js +705 -0
- package/test/layoutChordStrings.test.js +193 -0
- package/test/splitStringInRectangles.test.js +98 -0
- package/test/stringToFingering.test.js +1086 -0
- package/tsconfig.json +25 -0
- package/types/editableSVGuitar.d.ts +209 -0
- package/types/fingeringToString.d.ts +10 -0
- package/types/layoutChordStrings.d.ts +10 -0
- package/types/splitStringInRectangles.d.ts +18 -0
- package/types/stringToFingering.d.ts +10 -0
package/AGENTS.md
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
AGENTS.md - Repository Agent Guidelines
|
|
2
|
+
Build: `npm install`; Types: `npm run build:types` (tsc JSDoc declarations only).
|
|
3
|
+
Test all: `npm test` (runs Node builtin test runner on `test/*.test.js`).
|
|
4
|
+
Watch tests: `npm run test:watch`.
|
|
5
|
+
Single test file: `node --test test/editableSVGuitar.test.js`.
|
|
6
|
+
Single test by name: `node --test test/editableSVGuitar.test.js --test-name-pattern 'EditableSVGuitarChord'`.
|
|
7
|
+
No linter configured; keep style consistent; propose ESLint only if requested (do not add unasked).
|
|
8
|
+
Modules: ESM (`"type":"module"`); always include `.js` extension in relative imports.
|
|
9
|
+
Exports: prefer named exports; update `types/` via build when adding API.
|
|
10
|
+
Formatting: 2-space indent, semicolons, trailing commas only where existing pattern; keep lines < 100 chars.
|
|
11
|
+
Naming: constants/enums UPPER_SNAKE_CASE; functions & variables camelCase; generators use verbNoun (e.g., generateInversions).
|
|
12
|
+
Types: use JSDoc `@typedef`, `@template`, `@param`, `@returns`; keep `//@ts-check` at top of new JS files.
|
|
13
|
+
Data structures: prefer immutable operations; clearly document and minimize in-place mutation.
|
|
14
|
+
Tests: use `describe` + `test`; assertions via `node:assert/strict`; avoid flaky/time-based tests.
|
|
15
|
+
Test additions: place in `test/` with `.test.js`; keep one concern per `describe`; avoid console logs (remove debug prints).
|
|
16
|
+
Performance: prefer simple loops over heavy abstractions in hot paths; avoid allocating inside tight generators unnecessarily.
|
|
17
|
+
Public API stability: avoid breaking existing exported names; add new exports rather than renaming.
|
|
18
|
+
Do not add new tooling/config (linters, formatters, CI) unless explicitly requested.
|
package/FORMAT.md
ADDED
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
# How to represent a fingering using text
|
|
2
|
+
|
|
3
|
+
2 formats are supported. A concise ascii one that is designed to be edited easily and a nicer one that uses unicode, looks better but is more difficult to edit.
|
|
4
|
+
|
|
5
|
+
## General rules and semantic
|
|
6
|
+
The diagram represent a fragment of a guitar fretboard with low pitch string on the left and high pitch on the right. They are formed by 3 sections:
|
|
7
|
+
- title (optional)
|
|
8
|
+
- open strings (optional)
|
|
9
|
+
- fretboard (mandatory)
|
|
10
|
+
|
|
11
|
+
### String numbering
|
|
12
|
+
Strings are numbered 1-6 from right to left in the diagram. In standard guitar tuning:
|
|
13
|
+
- String 6 (leftmost) is the lowest pitch (E2)
|
|
14
|
+
- String 1 (rightmost) is the highest pitch (E4)
|
|
15
|
+
|
|
16
|
+
### Color values
|
|
17
|
+
The format supports two colors for fingering markers:
|
|
18
|
+
- `#000000` (black) for regular fingering positions
|
|
19
|
+
- `#e74c3c` (red/root marker color) for special positions (typically root notes)
|
|
20
|
+
|
|
21
|
+
Any color value other than `#000000` is treated as a root marker and rendered with the special marker symbol.
|
|
22
|
+
|
|
23
|
+
## ascii format
|
|
24
|
+
|
|
25
|
+
### title section
|
|
26
|
+
The title (optional) is max 15 characters all on the same line. If this section is included it is separated from the section underneath by a line of "#". The line is as long as the title above, with a minimum of 6 characters.
|
|
27
|
+
|
|
28
|
+
### open string section
|
|
29
|
+
The open string section is optional and separated from the section underneath by "------" or "======". This separator is always included as it is the first line of the fretboard section.
|
|
30
|
+
- "------" is used when no fret position is set, or when the fret position is written on the first line of the fretboard section (including position 1)
|
|
31
|
+
- "======" is used as an alternate representation when the fret position is 1 (in this case, the position number is not written on the fretboard line)
|
|
32
|
+
|
|
33
|
+
Note: Position 1 can be represented in two ways:
|
|
34
|
+
1. Using "------" with " 1" written on the first fretboard line
|
|
35
|
+
2. Using "======" with no position number on the fretboard line
|
|
36
|
+
|
|
37
|
+
This section contains up to 6 elements (one for each string). Trailing spaces are trimmed from the line. Each position can be:
|
|
38
|
+
- " " (space) means that the string at this position is neither muted nor played
|
|
39
|
+
- "x" means that the string at this position is muted
|
|
40
|
+
- "o" means that the string at this position is played (open string)
|
|
41
|
+
|
|
42
|
+
### fretboard section
|
|
43
|
+
This section is mandatory and at least 3 rows long (3 frets).
|
|
44
|
+
The first line can optionally have an indication of the starting fret on the left, right-justified in a 2-character field (e.g., " 5" for fret 5, "15" for fret 15).
|
|
45
|
+
|
|
46
|
+
These different characters are used:
|
|
47
|
+
- "|" indicates that there is no fingering in this position
|
|
48
|
+
- "o" indicates that this position is fingered with a regular dot (color #000000)
|
|
49
|
+
- "*" indicates that this position is fingered with a root marker (non-black color, typically #e74c3c)
|
|
50
|
+
- any other character is displayed as text on the fretboard at that position (commonly used for finger numbers or note names)
|
|
51
|
+
|
|
52
|
+
Examples:
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
A min
|
|
56
|
+
######
|
|
57
|
+
oo o
|
|
58
|
+
------
|
|
59
|
+
||||o|
|
|
60
|
+
||o*||
|
|
61
|
+
||||||
|
|
62
|
+
|
|
63
|
+
D
|
|
64
|
+
######
|
|
65
|
+
xoo
|
|
66
|
+
------
|
|
67
|
+
||||||
|
|
68
|
+
|||o|o
|
|
69
|
+
||||*|
|
|
70
|
+
|
|
71
|
+
G 7
|
|
72
|
+
######
|
|
73
|
+
xx
|
|
74
|
+
------
|
|
75
|
+
5||*|||
|
|
76
|
+
||||o|
|
|
77
|
+
|||o|o
|
|
78
|
+
|
|
79
|
+
E dom 7
|
|
80
|
+
#######
|
|
81
|
+
x x
|
|
82
|
+
------
|
|
83
|
+
|||3||
|
|
84
|
+
|51|||
|
|
85
|
+
||||7|
|
|
86
|
+
|
|
87
|
+
Dominant 7
|
|
88
|
+
##########
|
|
89
|
+
xx
|
|
90
|
+
======
|
|
91
|
+
||*|||
|
|
92
|
+
||||o|
|
|
93
|
+
|||o|o
|
|
94
|
+
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## unicode format
|
|
98
|
+
|
|
99
|
+
### title section
|
|
100
|
+
The title (optional) is max 15 characters all on the same line. If this section is included it is separated from the section underneath by a line of "‾". The line is as long as the title above and at least 11 characters
|
|
101
|
+
|
|
102
|
+
### open string section
|
|
103
|
+
The open string section is optional and separated from the section underneath by "┌─┬─┬─┬─┬─┐" or "╒═╤═╤═╤═╕". This separator is always included as it is the first line of the fretboard section.
|
|
104
|
+
- "┌─┬─┬─┬─┬─┐" is used when no fret position is set, or when the fret position is written on the second line of the fretboard section (including position 1)
|
|
105
|
+
- "╒═╤═╤═╤═╕" is used as an alternate representation when the fret position is 1 (in this case, the position number is not written on the fretboard)
|
|
106
|
+
|
|
107
|
+
Note: Position 1 can be represented in two ways:
|
|
108
|
+
1. Using "┌─┬─┬─┬─┬─┐" with " 1" written on the second line of the fretboard section
|
|
109
|
+
2. Using "╒═╤═╤═╤═╕" with no position number on the fretboard
|
|
110
|
+
|
|
111
|
+
This section contains up to 6 elements (one for each string) separated by spaces. Trailing spaces are trimmed from the line. Each position can be:
|
|
112
|
+
- " " (space) means that the string at this position is neither muted nor played
|
|
113
|
+
- "×" means that the string at this position is muted
|
|
114
|
+
- "○" means that the string at this position is played (open string)
|
|
115
|
+
|
|
116
|
+
### fretboard section
|
|
117
|
+
This section is mandatory and at least 3 frets long. It is built as a grid:
|
|
118
|
+
```
|
|
119
|
+
┌─┬─┬─┬─┬─┐
|
|
120
|
+
│ │ │ │ │ │
|
|
121
|
+
├─┼─┼─┼─┼─┤
|
|
122
|
+
│ │ │ │ │ │
|
|
123
|
+
├─┼─┼─┼─┼─┤
|
|
124
|
+
│ │ │ │ │ │
|
|
125
|
+
└─┴─┴─┴─┴─┘
|
|
126
|
+
```
|
|
127
|
+
The second line can optionally have an indication of the starting fret on the left, right-justified in a 2-character field (e.g., " 5" for fret 5, "15" for fret 15).
|
|
128
|
+
|
|
129
|
+
The even rows contain characters representing the fingering:
|
|
130
|
+
- "│" indicates that there is no fingering in this position
|
|
131
|
+
- "○" indicates that this position is fingered with a regular dot (color #000000)
|
|
132
|
+
- "●" indicates that this position is fingered with a root marker (non-black color, typically #e74c3c)
|
|
133
|
+
- any other character is displayed as text on the fretboard at that position (commonly used for finger numbers or note names)
|
|
134
|
+
|
|
135
|
+
Example:
|
|
136
|
+
```
|
|
137
|
+
A minor
|
|
138
|
+
‾‾‾‾‾‾‾‾‾‾‾
|
|
139
|
+
○ ○ ○
|
|
140
|
+
╒═╤═╤═╤═╤═╕
|
|
141
|
+
│ │ │ │ ○ │
|
|
142
|
+
├─┼─┼─┼─┼─┤
|
|
143
|
+
│ │ ○ ● │ │
|
|
144
|
+
├─┼─┼─┼─┼─┤
|
|
145
|
+
│ │ │ │ │ │
|
|
146
|
+
└─┴─┴─┴─┴─┘
|
|
147
|
+
|
|
148
|
+
D
|
|
149
|
+
‾‾‾‾‾‾‾‾‾‾‾
|
|
150
|
+
× ○ ○
|
|
151
|
+
╒═╤═╤═╤═╤═╕
|
|
152
|
+
│ │ │ │ │ │
|
|
153
|
+
├─┼─┼─┼─┼─┤
|
|
154
|
+
│ │ │ ○ │ ○
|
|
155
|
+
├─┼─┼─┼─┼─┤
|
|
156
|
+
│ │ │ │ ● │
|
|
157
|
+
└─┴─┴─┴─┴─┘
|
|
158
|
+
|
|
159
|
+
G 7
|
|
160
|
+
‾‾‾‾‾‾‾‾‾‾‾
|
|
161
|
+
× ×
|
|
162
|
+
┌─┬─┬─┬─┬─┐
|
|
163
|
+
5│ │ ● │ │ │
|
|
164
|
+
├─┼─┼─┼─┼─┤
|
|
165
|
+
│ │ │ │ ○ │
|
|
166
|
+
├─┼─┼─┼─┼─┤
|
|
167
|
+
│ │ │ ○ │ ○
|
|
168
|
+
└─┴─┴─┴─┴─┘
|
|
169
|
+
|
|
170
|
+
E dom 7
|
|
171
|
+
‾‾‾‾‾‾‾‾‾‾‾
|
|
172
|
+
× ×
|
|
173
|
+
┌─┬─┬─┬─┬─┐
|
|
174
|
+
│ │ │ 3 │ │
|
|
175
|
+
├─┼─┼─┼─┼─┤
|
|
176
|
+
│ 5 1 │ │ │
|
|
177
|
+
├─┼─┼─┼─┼─┤
|
|
178
|
+
│ │ │ │ 7 │
|
|
179
|
+
└─┴─┴─┴─┴─┘
|
|
180
|
+
|
|
181
|
+
Dominant 7
|
|
182
|
+
‾‾‾‾‾‾‾‾‾‾‾
|
|
183
|
+
× ×
|
|
184
|
+
╒═╤═╤═╤═╤═╕
|
|
185
|
+
│ │ ● │ │ │
|
|
186
|
+
├─┼─┼─┼─┼─┤
|
|
187
|
+
│ │ │ │ ○ │
|
|
188
|
+
├─┼─┼─┼─┼─┤
|
|
189
|
+
│ │ │ ○ │ ○
|
|
190
|
+
└─┴─┴─┴─┴─┘
|
|
191
|
+
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
## Edge cases and special behaviors
|
|
195
|
+
|
|
196
|
+
### Missing sections
|
|
197
|
+
- If no title is provided, the title and separator lines are omitted
|
|
198
|
+
- If no open strings are defined (no string with fret 0 or "x"), the open string section is omitted
|
|
199
|
+
- The fretboard section is always present (minimum 3 frets)
|
|
200
|
+
|
|
201
|
+
### Empty chords
|
|
202
|
+
An empty chord (no fingerings) renders as just the fretboard grid with no markers.
|
|
203
|
+
|
|
204
|
+
ASCII format:
|
|
205
|
+
```
|
|
206
|
+
------
|
|
207
|
+
||||||
|
|
208
|
+
||||||
|
|
209
|
+
||||||
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
Unicode format:
|
|
213
|
+
```
|
|
214
|
+
┌─┬─┬─┬─┬─┐
|
|
215
|
+
│ │ │ │ │ │
|
|
216
|
+
├─┼─┼─┼─┼─┤
|
|
217
|
+
│ │ │ │ │ │
|
|
218
|
+
├─┼─┼─┼─┼─┤
|
|
219
|
+
│ │ │ │ │ │
|
|
220
|
+
└─┴─┴─┴─┴─┘
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### All open strings
|
|
224
|
+
All six strings can be marked as open.
|
|
225
|
+
|
|
226
|
+
ASCII format:
|
|
227
|
+
```
|
|
228
|
+
E major
|
|
229
|
+
#######
|
|
230
|
+
oooooo
|
|
231
|
+
------
|
|
232
|
+
||||||
|
|
233
|
+
||||||
|
|
234
|
+
||||||
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
Unicode format:
|
|
238
|
+
```
|
|
239
|
+
E major
|
|
240
|
+
‾‾‾‾‾‾‾‾‾‾‾
|
|
241
|
+
○ ○ ○ ○ ○ ○
|
|
242
|
+
╒═╤═╤═╤═╤═╕
|
|
243
|
+
│ │ │ │ │ │
|
|
244
|
+
├─┼─┼─┼─┼─┤
|
|
245
|
+
│ │ │ │ │ │
|
|
246
|
+
├─┼─┼─┼─┼─┤
|
|
247
|
+
│ │ │ │ │ │
|
|
248
|
+
└─┴─┴─┴─┴─┘
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
### All muted strings
|
|
252
|
+
All six strings can be marked as muted.
|
|
253
|
+
|
|
254
|
+
ASCII format:
|
|
255
|
+
```
|
|
256
|
+
Muted
|
|
257
|
+
#####
|
|
258
|
+
xxxxxx
|
|
259
|
+
------
|
|
260
|
+
||||||
|
|
261
|
+
||||||
|
|
262
|
+
||||||
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
Unicode format:
|
|
266
|
+
```
|
|
267
|
+
Muted
|
|
268
|
+
‾‾‾‾‾‾‾‾‾‾‾
|
|
269
|
+
× × × × × ×
|
|
270
|
+
┌─┬─┬─┬─┬─┐
|
|
271
|
+
│ │ │ │ │ │
|
|
272
|
+
├─┼─┼─┼─┼─┤
|
|
273
|
+
│ │ │ │ │ │
|
|
274
|
+
├─┼─┼─┼─┼─┤
|
|
275
|
+
│ │ │ │ │ │
|
|
276
|
+
└─┴─┴─┴─┴─┘
|
|
277
|
+
```
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 text-guitar-chart
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Text Guitar Chart
|
|
2
|
+
|
|
3
|
+
This library allows to write fretboard charts in a text format that is easy to read. It also includes utilities to convert the charts in svg using [svguitar](https://github.com/omnibrain/svguitar).
|
|
4
|
+
|
|
5
|
+
See the [format](FORMAT.md)
|
|
6
|
+
|
|
7
|
+
# How to use
|
|
8
|
+
Use [the editor](https://sithmel.github.io/text-guitar-chart/) to edit the fingering you like. Copy paste the fretboard chart wherever you like!
|
|
9
|
+
|
|
10
|
+
# Utilities
|
|
11
|
+
Here is a list of utilities it provides:
|
|
12
|
+
- EditableSVGuitarChord an editable chord chart utility
|
|
13
|
+
- stringToFingering transforms a text representation of a fingering into data that can be used to render that fingering using SVGuitar
|
|
14
|
+
- fingeringToString transforms SVGuitar data format into a text representation of a fingering
|
|
15
|
+
|
|
16
|
+
## TypeScript Support
|
|
17
|
+
|
|
18
|
+
This library includes TypeScript declarations generated from JSDoc comments:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm run build:types
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Development
|
|
25
|
+
|
|
26
|
+
### Running Tests
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npm test
|
|
30
|
+
npm run test:watch # Watch mode
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Generate Type Declarations
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
npm run build:types
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## License
|
|
40
|
+
|
|
41
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
package/docs/app.js
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
//@ts-check
|
|
2
|
+
import { EditableSVGuitarChord } from '../lib/editableSVGuitar.js';
|
|
3
|
+
import { SVGuitarChord } from 'svguitar';
|
|
4
|
+
import splitStringInRectangles from '../lib/splitStringInRectangles.js';
|
|
5
|
+
import stringToFingering from '../lib/stringToFingering.js';
|
|
6
|
+
import layoutChordStrings from '../lib/layoutChordStrings.js';
|
|
7
|
+
|
|
8
|
+
/** @type {HTMLElement} */
|
|
9
|
+
const editor = /** @type {HTMLElement} */(document.getElementById('editor'));
|
|
10
|
+
/** @type {HTMLElement} */
|
|
11
|
+
const output = /** @type {HTMLElement} */(document.getElementById('output'));
|
|
12
|
+
/** @type {HTMLElement} */
|
|
13
|
+
const outputAscii = /** @type {HTMLElement} */(document.getElementById('output-ascii'));
|
|
14
|
+
/** @type {HTMLElement} */
|
|
15
|
+
const outputUnicode = /** @type {HTMLElement} */(document.getElementById('output-unicode'));
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
if (!editor || !outputAscii || !outputUnicode) {
|
|
19
|
+
throw new Error('Required DOM elements not found');
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const editable = new EditableSVGuitarChord(editor)
|
|
23
|
+
.chord({ fingers: [], barres: [] })
|
|
24
|
+
.configure({ frets: 5, noPosition: true })
|
|
25
|
+
.draw();
|
|
26
|
+
|
|
27
|
+
editable.onChange(() => {
|
|
28
|
+
updateJSON();
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
/** Update JSON panel */
|
|
32
|
+
function updateJSON() {
|
|
33
|
+
output.textContent = JSON.stringify(editable.getChord(), null, 2);
|
|
34
|
+
outputAscii.textContent = editable.toString({ useUnicode: false });
|
|
35
|
+
outputUnicode.textContent = editable.toString({ useUnicode: true });
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
document.getElementById('clear')?.addEventListener('click', () => {
|
|
39
|
+
editable.chord({ fingers: [], barres: [] }).redraw();
|
|
40
|
+
updateJSON();
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
document.getElementById('copy-json')?.addEventListener('click', () => {
|
|
44
|
+
navigator.clipboard.writeText(output.textContent || '').catch(err => {
|
|
45
|
+
console.error('Failed to copy JSON:', err);
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
document.getElementById('copy-ascii')?.addEventListener('click', () => {
|
|
50
|
+
navigator.clipboard.writeText(outputAscii.textContent || '').catch(err => {
|
|
51
|
+
console.error('Failed to copy ASCII:', err);
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
document.getElementById('copy-unicode')?.addEventListener('click', () => {
|
|
56
|
+
navigator.clipboard.writeText(outputUnicode.textContent || '').catch(err => {
|
|
57
|
+
console.error('Failed to copy Unicode:', err);
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
// Initial panel fill
|
|
62
|
+
updateJSON();
|
|
63
|
+
|
|
64
|
+
// Tab switching
|
|
65
|
+
document.getElementById('tab-editor')?.addEventListener('click', () => {
|
|
66
|
+
document.getElementById('tab-editor')?.classList.add('active');
|
|
67
|
+
document.getElementById('tab-batch')?.classList.remove('active');
|
|
68
|
+
document.getElementById('interactive-editor')?.classList.add('active');
|
|
69
|
+
document.getElementById('batch-converter')?.classList.remove('active');
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
document.getElementById('tab-batch')?.addEventListener('click', () => {
|
|
73
|
+
document.getElementById('tab-batch')?.classList.add('active');
|
|
74
|
+
document.getElementById('tab-editor')?.classList.remove('active');
|
|
75
|
+
document.getElementById('batch-converter')?.classList.add('active');
|
|
76
|
+
document.getElementById('interactive-editor')?.classList.remove('active');
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// Batch conversion
|
|
80
|
+
document.getElementById('convert-btn')?.addEventListener('click', () => {
|
|
81
|
+
const textarea = /** @type {HTMLTextAreaElement} */(document.getElementById('batch-input'));
|
|
82
|
+
const chordGrid = document.getElementById('chord-grid');
|
|
83
|
+
|
|
84
|
+
if (!textarea || !chordGrid) {
|
|
85
|
+
console.error('Required elements not found');
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const input = textarea.value;
|
|
90
|
+
if (!input.trim()) {
|
|
91
|
+
console.warn('No input provided');
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
try {
|
|
96
|
+
// Clear previous results
|
|
97
|
+
chordGrid.innerHTML = '';
|
|
98
|
+
|
|
99
|
+
// Split input into rectangles
|
|
100
|
+
const rectangles = splitStringInRectangles(input);
|
|
101
|
+
|
|
102
|
+
if (rectangles.length === 0) {
|
|
103
|
+
console.warn('No chord diagrams found in input');
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Convert each rectangle to a chord and render
|
|
108
|
+
rectangles.forEach((rectangle, index) => {
|
|
109
|
+
try {
|
|
110
|
+
const chordConfig = stringToFingering(rectangle);
|
|
111
|
+
if (chordConfig == null) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Create container for this chord
|
|
116
|
+
const container = document.createElement('div');
|
|
117
|
+
container.className = 'chord-container';
|
|
118
|
+
chordGrid.appendChild(container);
|
|
119
|
+
|
|
120
|
+
// Render the chord
|
|
121
|
+
const chart = new SVGuitarChord(container);
|
|
122
|
+
const frets = Math.max(...chordConfig.fingers.map(f => (typeof f[1] === 'number' ? f[1] : 0)), 3);
|
|
123
|
+
const noPosition = chordConfig.position === 0 || (chordConfig.position === undefined);
|
|
124
|
+
chart
|
|
125
|
+
.chord(chordConfig)
|
|
126
|
+
.configure({ frets, noPosition })
|
|
127
|
+
.draw();
|
|
128
|
+
} catch (err) {
|
|
129
|
+
console.error(`Error rendering chord ${index + 1}:`, err);
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
} catch (err) {
|
|
133
|
+
console.error('Error during batch conversion:', err);
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
*
|
|
139
|
+
* @param {number} columnNumber
|
|
140
|
+
*/
|
|
141
|
+
function layout (columnNumber){
|
|
142
|
+
const textarea = /** @type {HTMLTextAreaElement} */(document.getElementById('batch-input'));
|
|
143
|
+
if (!textarea) {
|
|
144
|
+
console.error('Required elements not found');
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const input = textarea.value;
|
|
149
|
+
if (!input.trim()) {
|
|
150
|
+
console.warn('No input provided');
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
// Split input into rectangles
|
|
154
|
+
const rectangles = splitStringInRectangles(input);
|
|
155
|
+
const layout = layoutChordStrings(rectangles, columnNumber, 3);
|
|
156
|
+
textarea.value = layout;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Batch conversion
|
|
160
|
+
document.getElementById('layout-2-btn')?.addEventListener('click', () => {
|
|
161
|
+
layout(2);
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
// Batch conversion
|
|
165
|
+
document.getElementById('layout-3-btn')?.addEventListener('click', () => {
|
|
166
|
+
layout(3);
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
// Batch conversion
|
|
170
|
+
document.getElementById('layout-4-btn')?.addEventListener('click', () => {
|
|
171
|
+
layout(4);
|
|
172
|
+
});
|