abcjs 6.1.0 → 6.1.3
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/README.md +4 -0
- package/RELEASE.md +29 -0
- package/SECURITY.md +9 -0
- package/abcjs-audio.css +1 -0
- package/dist/abcjs-basic-min.js +2 -2
- package/dist/abcjs-basic.js +151 -130
- package/dist/abcjs-basic.js.map +1 -1
- package/dist/abcjs-plugin-min.js +2 -2
- package/package.json +1 -1
- package/src/api/abc_tunebook_svg.js +2 -98
- package/src/tablatures/tab-renderer.js +1 -1
- package/src/write/abc_engraver_controller.js +72 -1
- package/src/write/draw/draw.js +8 -0
- package/src/write/draw/staff-group.js +5 -5
- package/src/write/selection.js +48 -12
- package/src/write/svg.js +1 -1
- package/types/index.d.ts +44 -0
- package/version.js +1 -1
package/package.json
CHANGED
|
@@ -59,96 +59,6 @@ function renderOne(div, tune, params, tuneNumber, lineOffset) {
|
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
function renderEachLineSeparately(div, tune, params, tuneNumber) {
|
|
63
|
-
function initializeTuneLine(tune) {
|
|
64
|
-
var obj = new Tune();
|
|
65
|
-
obj.formatting = tune.formatting;
|
|
66
|
-
obj.media = tune.media;
|
|
67
|
-
obj.version = tune.version;
|
|
68
|
-
return obj;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// Before rendering, chop up the returned tune into an array where each element is a line.
|
|
72
|
-
// The first element of the array gets the title and other items that go on top, the last element
|
|
73
|
-
// of the array gets the extra text that goes on bottom. Each element gets any non-music info that comes before it.
|
|
74
|
-
var tunes = [];
|
|
75
|
-
var tuneLine;
|
|
76
|
-
for (var i = 0; i < tune.lines.length; i++) {
|
|
77
|
-
var line = tune.lines[i];
|
|
78
|
-
if (!tuneLine)
|
|
79
|
-
tuneLine = initializeTuneLine(tune);
|
|
80
|
-
|
|
81
|
-
if (i === 0) {
|
|
82
|
-
// These items go on top of the music
|
|
83
|
-
tuneLine.copyTopInfo(tune);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
// push the lines until we get to a music line
|
|
87
|
-
tuneLine.lines.push(line);
|
|
88
|
-
if (line.staff) {
|
|
89
|
-
tunes.push(tuneLine);
|
|
90
|
-
tuneLine = undefined;
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
// Add any extra stuff to the last line.
|
|
94
|
-
if (tuneLine) {
|
|
95
|
-
var lastLine = tunes[tunes.length-1];
|
|
96
|
-
for (var j = 0; j < tuneLine.lines.length; j++)
|
|
97
|
-
lastLine.lines.push(tuneLine.lines[j]);
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
// These items go below the music
|
|
101
|
-
tuneLine = tunes[tunes.length-1];
|
|
102
|
-
tuneLine.copyBottomInfo(tune);
|
|
103
|
-
|
|
104
|
-
// Now create sub-divs and render each line. Need to copy the params to change the padding for the interior slices.
|
|
105
|
-
var ep = {};
|
|
106
|
-
for (var key in params) {
|
|
107
|
-
if (params.hasOwnProperty(key)) {
|
|
108
|
-
ep[key] = params[key];
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
var origPaddingTop = ep.paddingtop;
|
|
112
|
-
var origPaddingBottom = ep.paddingbottom;
|
|
113
|
-
var currentScrollY = div.parentNode.scrollTop; // If there is scrolling it will be lost during the redraw so remember it.
|
|
114
|
-
var currentScrollX = div.parentNode.scrollLeft;
|
|
115
|
-
div.innerHTML = "";
|
|
116
|
-
var lineCount = 0;
|
|
117
|
-
for (var k = 0; k < tunes.length; k++) {
|
|
118
|
-
var lineEl = document.createElement("div");
|
|
119
|
-
div.appendChild(lineEl);
|
|
120
|
-
|
|
121
|
-
if (k === 0) {
|
|
122
|
-
ep.paddingtop = origPaddingTop;
|
|
123
|
-
ep.paddingbottom = 0;
|
|
124
|
-
} else if (k === tunes.length-1) {
|
|
125
|
-
ep.paddingtop = 10;
|
|
126
|
-
ep.paddingbottom = origPaddingBottom;
|
|
127
|
-
} else {
|
|
128
|
-
ep.paddingtop = 10;
|
|
129
|
-
ep.paddingbottom = 0;
|
|
130
|
-
}
|
|
131
|
-
if (k < tunes.length-1) {
|
|
132
|
-
// If it is not the last line, force stretchlast. If it is, stretchlast might have been set by the input parameters.
|
|
133
|
-
tunes[k].formatting = parseCommon.clone(tunes[k].formatting);
|
|
134
|
-
tunes[k].formatting.stretchlast = true;
|
|
135
|
-
}
|
|
136
|
-
renderOne(lineEl, tunes[k], ep, tuneNumber, lineCount);
|
|
137
|
-
lineCount += tunes[k].lines.length;
|
|
138
|
-
if (k === 0)
|
|
139
|
-
tune.engraver = tunes[k].engraver;
|
|
140
|
-
else {
|
|
141
|
-
if (!tune.engraver.staffgroups)
|
|
142
|
-
tune.engraver.staffgroups = tunes[k].engraver.staffgroups;
|
|
143
|
-
else if (tunes[k].engraver.staffgroups.length > 0)
|
|
144
|
-
tune.engraver.staffgroups.push(tunes[k].engraver.staffgroups[0]);
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
if (currentScrollX || currentScrollY) {
|
|
148
|
-
div.parentNode.scrollTo(currentScrollX, currentScrollY);
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
62
|
// A quick way to render a tune from javascript when interactivity is not required.
|
|
153
63
|
// This is used when a javascript routine has some abc text that it wants to render
|
|
154
64
|
// in a div or collection of divs. One tune or many can be rendered.
|
|
@@ -214,10 +124,7 @@ var renderAbc = function(output, abc, parserParams, engraverParams, renderParams
|
|
|
214
124
|
tune = doLineWrapping(div, tune, tuneNumber, abcString, params);
|
|
215
125
|
return tune;
|
|
216
126
|
}
|
|
217
|
-
|
|
218
|
-
renderOne(div, tune, params, tuneNumber, 0);
|
|
219
|
-
else
|
|
220
|
-
renderEachLineSeparately(div, tune, params, tuneNumber);
|
|
127
|
+
renderOne(div, tune, params, tuneNumber, 0);
|
|
221
128
|
if (removeDiv)
|
|
222
129
|
div.parentNode.removeChild(div);
|
|
223
130
|
return null;
|
|
@@ -239,10 +146,7 @@ function doLineWrapping(div, tune, tuneNumber, abcString, params) {
|
|
|
239
146
|
if (warnings)
|
|
240
147
|
tune.warnings = warnings;
|
|
241
148
|
}
|
|
242
|
-
|
|
243
|
-
renderOne(div, tune, ret.revisedParams, tuneNumber, 0);
|
|
244
|
-
else
|
|
245
|
-
renderEachLineSeparately(div, tune, ret.revisedParams, tuneNumber);
|
|
149
|
+
renderOne(div, tune, ret.revisedParams, tuneNumber, 0);
|
|
246
150
|
tune.explanation = ret.explanation;
|
|
247
151
|
return tune;
|
|
248
152
|
}
|
|
@@ -198,7 +198,7 @@ TabRenderer.prototype.doLayout = function () {
|
|
|
198
198
|
var padd = 3;
|
|
199
199
|
var prevIndex = this.staffIndex;
|
|
200
200
|
var previousStaff = staffGroup.staffs[prevIndex];
|
|
201
|
-
var tabTop =
|
|
201
|
+
var tabTop = this.tabSize + padd - previousStaff.bottom - lyricsHeight;
|
|
202
202
|
if (previousStaff.isTabStaff) {
|
|
203
203
|
tabTop = previousStaff.top;
|
|
204
204
|
}
|
|
@@ -32,6 +32,7 @@ var tablatures = require('../api/abc_tablatures');
|
|
|
32
32
|
*/
|
|
33
33
|
var EngraverController = function(paper, params) {
|
|
34
34
|
params = params || {};
|
|
35
|
+
this.oneSvgPerLine = params.oneSvgPerLine;
|
|
35
36
|
this.selectionColor = params.selectionColor;
|
|
36
37
|
this.dragColor = params.dragColor ? params.dragColor : params.selectionColor;
|
|
37
38
|
this.dragging = !!params.dragging;
|
|
@@ -246,9 +247,79 @@ EngraverController.prototype.engraveTune = function (abcTune, tuneNumber, lineOf
|
|
|
246
247
|
this.staffgroups = ret.staffgroups;
|
|
247
248
|
this.selectables = ret.selectables;
|
|
248
249
|
|
|
249
|
-
|
|
250
|
+
if (this.oneSvgPerLine) {
|
|
251
|
+
var div = this.renderer.paper.svg.parentNode
|
|
252
|
+
this.svgs = splitSvgIntoLines(div, abcTune.metaText.title, this.responsive)
|
|
253
|
+
} else {
|
|
254
|
+
this.svgs = [this.renderer.paper.svg];
|
|
255
|
+
}
|
|
256
|
+
setupSelection(this, this.svgs);
|
|
250
257
|
};
|
|
251
258
|
|
|
259
|
+
function splitSvgIntoLines(output, title, responsive) {
|
|
260
|
+
// Each line is a top level <g> in the svg. To split it into separate
|
|
261
|
+
// svgs iterate through each of those and put them in a new svg. Since
|
|
262
|
+
// they are placed absolutely, the viewBox needs to be manipulated to
|
|
263
|
+
// get the correct vertical positioning.
|
|
264
|
+
// We copy all the attributes from the original svg except for the aria-label
|
|
265
|
+
// since we want that to include a count. And the height is now a fraction of the original svg.
|
|
266
|
+
if (!title) title = "Untitled"
|
|
267
|
+
var source = output.querySelector("svg")
|
|
268
|
+
if (responsive === 'resize')
|
|
269
|
+
output.style.paddingBottom = ''
|
|
270
|
+
var style = source.querySelector("style")
|
|
271
|
+
var width = responsive === 'resize' ? source.viewBox.baseVal.width : source.getAttribute("width")
|
|
272
|
+
var sections = output.querySelectorAll("svg > g") // each section is a line, or the top matter or the bottom matter, or text that has been inserted.
|
|
273
|
+
var nextTop = 0 // There are often gaps between the elements for spacing, so the actual top and height needs to be inferred.
|
|
274
|
+
var wrappers = [] // Create all the elements and place them at once because we use the current svg to get data. It would disappear after placing the first line.
|
|
275
|
+
var svgs = []
|
|
276
|
+
for (var i = 0; i < sections.length; i++) {
|
|
277
|
+
var section = sections[i]
|
|
278
|
+
var box = section.getBBox()
|
|
279
|
+
var gapBetweenLines = box.y - nextTop // take the margin into account
|
|
280
|
+
var height = box.height + gapBetweenLines;
|
|
281
|
+
var wrapper = document.createElement("div");
|
|
282
|
+
var divStyles = "overflow: hidden;"
|
|
283
|
+
if (responsive !== 'resize')
|
|
284
|
+
divStyles += "height:"+height+"px;"
|
|
285
|
+
wrapper.setAttribute("style", divStyles)
|
|
286
|
+
var svg = duplicateSvg(source)
|
|
287
|
+
var fullTitle = "Sheet Music for \"" + title + "\" section " + (i+1)
|
|
288
|
+
svg.setAttribute("aria-label", fullTitle)
|
|
289
|
+
if (responsive !== 'resize')
|
|
290
|
+
svg.setAttribute("height", height)
|
|
291
|
+
if (responsive === 'resize')
|
|
292
|
+
svg.style.position = ''
|
|
293
|
+
svg.setAttribute("viewBox", "0 " + nextTop + " " + width + " " + height )
|
|
294
|
+
svg.appendChild(style.cloneNode(true))
|
|
295
|
+
var titleEl = document.createElement("title")
|
|
296
|
+
titleEl.innerText = fullTitle
|
|
297
|
+
svg.appendChild(titleEl)
|
|
298
|
+
svg.appendChild(section)
|
|
299
|
+
|
|
300
|
+
wrapper.appendChild(svg)
|
|
301
|
+
svgs.push(svg)
|
|
302
|
+
output.appendChild(wrapper)
|
|
303
|
+
//wrappers.push(wrapper)
|
|
304
|
+
nextTop = box.y+box.height
|
|
305
|
+
}
|
|
306
|
+
// for (i = 0; i < wrappers.length; i++)
|
|
307
|
+
// output.appendChild(wrappers[i])
|
|
308
|
+
output.removeChild(source)
|
|
309
|
+
return svgs;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
function duplicateSvg(source) {
|
|
313
|
+
var svgNS = "http://www.w3.org/2000/svg";
|
|
314
|
+
var svg = document.createElementNS(svgNS, "svg");
|
|
315
|
+
for (var i = 0; i < source.attributes.length; i++) {
|
|
316
|
+
var attr = source.attributes[i];
|
|
317
|
+
if (attr.name !== "height" && attr.name != "aria-label")
|
|
318
|
+
svg.setAttribute(attr.name, attr.value)
|
|
319
|
+
}
|
|
320
|
+
return svg;
|
|
321
|
+
}
|
|
322
|
+
|
|
252
323
|
EngraverController.prototype.getDim = function(historyEl) {
|
|
253
324
|
// Get the dimensions on demand because the getBBox call is expensive.
|
|
254
325
|
if (!historyEl.dim) {
|
package/src/write/draw/draw.js
CHANGED
|
@@ -6,14 +6,17 @@ var Selectables = require('./selectables');
|
|
|
6
6
|
|
|
7
7
|
function draw(renderer, classes, abcTune, width, maxWidth, responsive, scale, selectTypes, tuneNumber, lineOffset) {
|
|
8
8
|
var selectables = new Selectables(renderer.paper, selectTypes, tuneNumber);
|
|
9
|
+
renderer.paper.openGroup()
|
|
9
10
|
renderer.moveY(renderer.padding.top);
|
|
10
11
|
nonMusic(renderer, abcTune.topText, selectables);
|
|
12
|
+
renderer.paper.closeGroup()
|
|
11
13
|
renderer.moveY(renderer.spacing.music);
|
|
12
14
|
var staffgroups = [];
|
|
13
15
|
for (var line = 0; line < abcTune.lines.length; line++) {
|
|
14
16
|
classes.incrLine();
|
|
15
17
|
var abcLine = abcTune.lines[line];
|
|
16
18
|
if (abcLine.staff) {
|
|
19
|
+
renderer.paper.openGroup()
|
|
17
20
|
if (abcLine.vskip) {
|
|
18
21
|
renderer.moveY(abcLine.vskip);
|
|
19
22
|
}
|
|
@@ -22,15 +25,20 @@ function draw(renderer, classes, abcTune, width, maxWidth, responsive, scale, se
|
|
|
22
25
|
var staffgroup = engraveStaffLine(renderer, abcLine.staffGroup, selectables,line);
|
|
23
26
|
staffgroup.line = lineOffset+line; // If there are non-music lines then the staffgroup array won't line up with the line array, so this keeps track.
|
|
24
27
|
staffgroups.push(staffgroup);
|
|
28
|
+
renderer.paper.closeGroup()
|
|
25
29
|
} else if (abcLine.nonMusic) {
|
|
30
|
+
renderer.paper.openGroup()
|
|
26
31
|
nonMusic(renderer, abcLine.nonMusic, selectables);
|
|
32
|
+
renderer.paper.closeGroup()
|
|
27
33
|
}
|
|
28
34
|
}
|
|
29
35
|
|
|
30
36
|
classes.reset();
|
|
31
37
|
if (abcTune.bottomText && abcTune.bottomText.rows && abcTune.bottomText.rows.length > 0) {
|
|
38
|
+
renderer.paper.openGroup()
|
|
32
39
|
renderer.moveY(24); // TODO-PER: Empirically discovered. What variable should this be?
|
|
33
40
|
nonMusic(renderer, abcTune.bottomText, selectables);
|
|
41
|
+
renderer.paper.closeGroup()
|
|
34
42
|
}
|
|
35
43
|
setPaperSize(renderer, maxWidth, scale, responsive);
|
|
36
44
|
return { staffgroups: staffgroups, selectables: selectables.getElements() };
|
|
@@ -15,7 +15,7 @@ function drawStaffGroup(renderer, params, selectables,lineNumber) {
|
|
|
15
15
|
var colorIndex;
|
|
16
16
|
|
|
17
17
|
// An invisible marker is useful to be able to find where each system starts.
|
|
18
|
-
addInvisibleMarker(renderer, "abcjs-top-of-system");
|
|
18
|
+
//addInvisibleMarker(renderer, "abcjs-top-of-system");
|
|
19
19
|
|
|
20
20
|
var startY = renderer.y; // So that it can be restored after we're done.
|
|
21
21
|
// Set the absolute Y position for each staff here, so the voice drawing below can just use if.
|
|
@@ -177,10 +177,10 @@ function printBrace(renderer, absoluteY, brace, index, selectables) {
|
|
|
177
177
|
}
|
|
178
178
|
}
|
|
179
179
|
|
|
180
|
-
function addInvisibleMarker(renderer, className) {
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
}
|
|
180
|
+
// function addInvisibleMarker(renderer, className) {
|
|
181
|
+
// var y = Math.round(renderer.y);
|
|
182
|
+
// renderer.paper.pathToBack({path:"M 0 " + y + " L 0 0", stroke:"none", fill:"none", "stroke-opacity": 0, "fill-opacity": 0, 'class': renderer.controller.classes.generate(className), 'data-vertical': y });
|
|
183
|
+
// }
|
|
184
184
|
|
|
185
185
|
function boxAllElements(renderer, voices, which) {
|
|
186
186
|
for (var i = 0; i < which.length; i++) {
|
package/src/write/selection.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
var spacing = require('./abc_spacing');
|
|
2
2
|
|
|
3
|
-
function setupSelection(engraver) {
|
|
3
|
+
function setupSelection(engraver, svgs) {
|
|
4
4
|
engraver.rangeHighlight = rangeHighlight;
|
|
5
5
|
if (engraver.dragging) {
|
|
6
6
|
for (var h = 0; h < engraver.selectables.length; h++) {
|
|
@@ -14,14 +14,21 @@ function setupSelection(engraver) {
|
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
16
|
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
for (var i = 0; i < svgs.length; i++) {
|
|
18
|
+
svgs[i].addEventListener('touchstart', mouseDown.bind(engraver));
|
|
19
|
+
svgs[i].addEventListener('touchmove', mouseMove.bind(engraver));
|
|
20
|
+
svgs[i].addEventListener('touchend', mouseUp.bind(engraver));
|
|
21
|
+
svgs[i].addEventListener('mousedown', mouseDown.bind(engraver));
|
|
22
|
+
svgs[i].addEventListener('mousemove', mouseMove.bind(engraver));
|
|
23
|
+
svgs[i].addEventListener('mouseup', mouseUp.bind(engraver));
|
|
24
|
+
}
|
|
20
25
|
}
|
|
21
26
|
|
|
22
|
-
function getCoord(ev
|
|
27
|
+
function getCoord(ev) {
|
|
23
28
|
var scaleX = 1;
|
|
24
29
|
var scaleY = 1;
|
|
30
|
+
var svg = ev.target.closest('svg')
|
|
31
|
+
var yOffset = 0
|
|
25
32
|
|
|
26
33
|
// when renderer.options.responsive === 'resize' the click coords are in relation to the HTML
|
|
27
34
|
// element, we need to convert to the SVG viewBox coords
|
|
@@ -31,6 +38,7 @@ function getCoord(ev, svg) {
|
|
|
31
38
|
scaleX = svg.viewBox.baseVal.width / svg.clientWidth
|
|
32
39
|
if (svg.viewBox.baseVal.height !== 0)
|
|
33
40
|
scaleY = svg.viewBox.baseVal.height / svg.clientHeight
|
|
41
|
+
yOffset = svg.viewBox.baseVal.y
|
|
34
42
|
}
|
|
35
43
|
|
|
36
44
|
var svgClicked = ev.target.tagName === "svg";
|
|
@@ -48,7 +56,7 @@ function getCoord(ev, svg) {
|
|
|
48
56
|
y = y * scaleY;
|
|
49
57
|
//console.log(x, y)
|
|
50
58
|
|
|
51
|
-
return [x, y];
|
|
59
|
+
return [x, y+yOffset];
|
|
52
60
|
}
|
|
53
61
|
|
|
54
62
|
function elementFocused(ev) {
|
|
@@ -120,7 +128,7 @@ function keyboardSelection(ev) {
|
|
|
120
128
|
|
|
121
129
|
function findElementInHistory(selectables, el) {
|
|
122
130
|
for (var i = 0; i < selectables.length; i++) {
|
|
123
|
-
if (el === selectables[i].svgEl)
|
|
131
|
+
if (el.dataset.index === selectables[i].svgEl.dataset.index)
|
|
124
132
|
return i;
|
|
125
133
|
}
|
|
126
134
|
return -1;
|
|
@@ -216,7 +224,7 @@ function getMousePosition(self, ev) {
|
|
|
216
224
|
//console.log("clicked on", clickedOn, x, y, self.selectables[clickedOn].svgEl.getBBox(), ev.target.getBBox());
|
|
217
225
|
} else {
|
|
218
226
|
// See if they clicked close to an element.
|
|
219
|
-
box = getCoord(ev
|
|
227
|
+
box = getCoord(ev);
|
|
220
228
|
x = box[0];
|
|
221
229
|
y = box[1];
|
|
222
230
|
clickedOn = findElementByCoord(self, x, y);
|
|
@@ -225,13 +233,30 @@ function getMousePosition(self, ev) {
|
|
|
225
233
|
return { x: x, y: y, clickedOn: clickedOn };
|
|
226
234
|
}
|
|
227
235
|
|
|
236
|
+
function attachMissingTouchEventAttributes(touchEv) {
|
|
237
|
+
var rect = touchEv.target.getBoundingClientRect();
|
|
238
|
+
var offsetX = touchEv.touches[0].pageX - rect.left;
|
|
239
|
+
var offsetY = touchEv.touches[0].pageY - rect.top;
|
|
240
|
+
|
|
241
|
+
touchEv.touches[0].offsetX = offsetX;
|
|
242
|
+
touchEv.touches[0].offsetY = offsetY;
|
|
243
|
+
|
|
244
|
+
touchEv.touches[0].layerX = touchEv.touches[0].pageX;
|
|
245
|
+
touchEv.touches[0].layerY = touchEv.touches[0].pageY;
|
|
246
|
+
}
|
|
247
|
+
|
|
228
248
|
function mouseDown(ev) {
|
|
229
249
|
// "this" is the EngraverController because of the bind(this) when setting the event listener.
|
|
250
|
+
var _ev = ev;
|
|
251
|
+
if (ev.type === 'touchstart') {
|
|
252
|
+
attachMissingTouchEventAttributes(ev);
|
|
253
|
+
_ev = ev.touches[0];
|
|
254
|
+
}
|
|
230
255
|
|
|
231
|
-
var positioning = getMousePosition(this,
|
|
256
|
+
var positioning = getMousePosition(this, _ev);
|
|
232
257
|
|
|
233
258
|
// Only start dragging if the user clicked close enough to an element and clicked with the main mouse button.
|
|
234
|
-
if (positioning.clickedOn >= 0 && ev.button === 0) {
|
|
259
|
+
if (positioning.clickedOn >= 0 && (ev.type === 'touchstart' || ev.button === 0)) {
|
|
235
260
|
this.dragTarget = this.selectables[positioning.clickedOn];
|
|
236
261
|
this.dragIndex = positioning.clickedOn;
|
|
237
262
|
this.dragMechanism = "mouse";
|
|
@@ -244,12 +269,18 @@ function mouseDown(ev) {
|
|
|
244
269
|
}
|
|
245
270
|
|
|
246
271
|
function mouseMove(ev) {
|
|
272
|
+
var _ev = ev;
|
|
273
|
+
if (ev.type === 'touchmove') {
|
|
274
|
+
attachMissingTouchEventAttributes(ev);
|
|
275
|
+
_ev = ev.touches[0];
|
|
276
|
+
}
|
|
277
|
+
this.lastTouchMove = ev;
|
|
247
278
|
// "this" is the EngraverController because of the bind(this) when setting the event listener.
|
|
248
279
|
|
|
249
280
|
if (!this.dragTarget || !this.dragging || !this.dragTarget.isDraggable || this.dragMechanism !== 'mouse')
|
|
250
281
|
return;
|
|
251
282
|
|
|
252
|
-
var positioning = getMousePosition(this,
|
|
283
|
+
var positioning = getMousePosition(this, _ev);
|
|
253
284
|
|
|
254
285
|
var yDist = Math.round((positioning.y - this.dragMouseStart.y)/spacing.STEP);
|
|
255
286
|
if (yDist !== this.dragYStep) {
|
|
@@ -260,6 +291,11 @@ function mouseMove(ev) {
|
|
|
260
291
|
|
|
261
292
|
function mouseUp(ev) {
|
|
262
293
|
// "this" is the EngraverController because of the bind(this) when setting the event listener.
|
|
294
|
+
var _ev = ev;
|
|
295
|
+
if (ev.type === 'touchend') {
|
|
296
|
+
attachMissingTouchEventAttributes(this.lastTouchMove);
|
|
297
|
+
_ev = this.lastTouchMove.touches[0];
|
|
298
|
+
}
|
|
263
299
|
|
|
264
300
|
if (!this.dragTarget)
|
|
265
301
|
return;
|
|
@@ -270,7 +306,7 @@ function mouseUp(ev) {
|
|
|
270
306
|
this.dragTarget.absEl.highlight(undefined, this.selectionColor);
|
|
271
307
|
}
|
|
272
308
|
|
|
273
|
-
notifySelect.bind(this)(this.dragTarget, this.dragYStep, this.selectables.length, this.dragIndex,
|
|
309
|
+
notifySelect.bind(this)(this.dragTarget, this.dragYStep, this.selectables.length, this.dragIndex, _ev);
|
|
274
310
|
if (this.dragTarget.svgEl && this.dragTarget.svgEl.focus) {
|
|
275
311
|
this.dragTarget.svgEl.focus();
|
|
276
312
|
this.dragTarget = null;
|
package/src/write/svg.js
CHANGED
|
@@ -307,7 +307,7 @@ Svg.prototype.closeGroup = function() {
|
|
|
307
307
|
var g = this.currentGroup.shift();
|
|
308
308
|
if (g && g.children.length === 0) {
|
|
309
309
|
// If nothing was added to the group it is because all the elements were invisible. We don't need the group, then.
|
|
310
|
-
|
|
310
|
+
g.parentElement.removeChild(g);
|
|
311
311
|
return null;
|
|
312
312
|
}
|
|
313
313
|
return g;
|
package/types/index.d.ts
CHANGED
|
@@ -171,6 +171,8 @@ declare module 'abcjs' {
|
|
|
171
171
|
|
|
172
172
|
export type AbsoluteElement = any; // TODO
|
|
173
173
|
|
|
174
|
+
export type AbstractEngraver = any;
|
|
175
|
+
|
|
174
176
|
export type NoteProperties = any; // TODO
|
|
175
177
|
|
|
176
178
|
export type AudioTrackCommand = 'program' | 'text' | 'note';
|
|
@@ -504,6 +506,34 @@ declare module 'abcjs' {
|
|
|
504
506
|
wordsfont: Font;
|
|
505
507
|
}
|
|
506
508
|
|
|
509
|
+
export interface EngraverController {
|
|
510
|
+
classes: any;
|
|
511
|
+
dragColor: string;
|
|
512
|
+
dragIndex: number;
|
|
513
|
+
dragMouseStart: { x: number, y: number; };
|
|
514
|
+
dragTarget: null | any;
|
|
515
|
+
dragYStep: number;
|
|
516
|
+
dragging: boolean;
|
|
517
|
+
engraver: AbstractEngraver;
|
|
518
|
+
getFontAndAttr: any;
|
|
519
|
+
getTextSize: any;
|
|
520
|
+
listeners: [ClickListener];
|
|
521
|
+
rangeHighlight: any;
|
|
522
|
+
renderer: any;
|
|
523
|
+
responsive?: boolean;
|
|
524
|
+
scale: number;
|
|
525
|
+
initialClef?: any;
|
|
526
|
+
selectTypes: boolean | Array<DragTypes>;
|
|
527
|
+
selectables: Array<Selectable>;
|
|
528
|
+
selected: Array<any>;
|
|
529
|
+
selectionColor: string;
|
|
530
|
+
space: number;
|
|
531
|
+
staffgroups: [any];
|
|
532
|
+
staffwidthPrint: number;
|
|
533
|
+
staffwidthScreen: number;
|
|
534
|
+
width: number;
|
|
535
|
+
}
|
|
536
|
+
|
|
507
537
|
export interface MetaText {
|
|
508
538
|
"abc-copyright"?: string;
|
|
509
539
|
"abc-creator"?: string;
|
|
@@ -712,6 +742,7 @@ declare module 'abcjs' {
|
|
|
712
742
|
|
|
713
743
|
export interface TuneObject {
|
|
714
744
|
formatting: Formatting;
|
|
745
|
+
engraver?: EngraverController;
|
|
715
746
|
lines: Array<TuneLine>;
|
|
716
747
|
media: Media;
|
|
717
748
|
metaText: MetaText;
|
|
@@ -732,12 +763,23 @@ declare module 'abcjs' {
|
|
|
732
763
|
millisecondsPerMeasure: NumberFunction;
|
|
733
764
|
setTiming: (bpm?: number, measuresOfDelay? : number) => void;
|
|
734
765
|
setUpAudio: (options: SynthOptions) => AudioTracks;
|
|
766
|
+
makeVoicesArray: () => Array<Selectable[]>
|
|
735
767
|
lineBreaks?: Array<number>;
|
|
736
768
|
visualTranspose?: number;
|
|
737
769
|
}
|
|
738
770
|
|
|
739
771
|
export type TuneObjectArray = [TuneObject]
|
|
740
772
|
|
|
773
|
+
export interface Selectable {
|
|
774
|
+
absEl: AbsoluteElement;
|
|
775
|
+
isDraggable: boolean;
|
|
776
|
+
staffPos: {
|
|
777
|
+
height: number;
|
|
778
|
+
top: number;
|
|
779
|
+
zero: number;
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
|
|
741
783
|
export interface AbcElem {
|
|
742
784
|
el_type: string //TODO enumerate these
|
|
743
785
|
abselem: any;
|
|
@@ -1091,6 +1133,8 @@ declare module 'abcjs' {
|
|
|
1091
1133
|
|
|
1092
1134
|
export function numberOfTunes(abc: string) : number;
|
|
1093
1135
|
export function extractMeasures(abc: string) : Array<MeasureList>;
|
|
1136
|
+
|
|
1137
|
+
export function strTranspose(originalAbc: string, visualObj: TuneObject, steps: number): string;
|
|
1094
1138
|
|
|
1095
1139
|
//
|
|
1096
1140
|
// Glyph
|
package/version.js
CHANGED