|
|
|
|
|
|
|
|
var TieElem = function TieElem(options) { |
|
|
this.type = "TieElem"; |
|
|
|
|
|
this.anchor1 = options.anchor1; |
|
|
this.anchor2 = options.anchor2; |
|
|
if (options.isGrace) |
|
|
this.isGrace = true; |
|
|
if (options.fixedY) |
|
|
this.fixedY = true; |
|
|
if (options.stemDir) |
|
|
this.stemDir = options.stemDir; |
|
|
if (options.voiceNumber !== undefined) |
|
|
this.voiceNumber = options.voiceNumber; |
|
|
if (options.style !== undefined) |
|
|
this.dotted = true; |
|
|
this.internalNotes = []; |
|
|
}; |
|
|
|
|
|
TieElem.prototype.addInternalNote = function (note) { |
|
|
this.internalNotes.push(note); |
|
|
}; |
|
|
|
|
|
TieElem.prototype.setEndAnchor = function (anchor2) { |
|
|
|
|
|
this.anchor2 = anchor2; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (this.anchor1) { |
|
|
this.top = Math.max(this.anchor1.pitch, this.anchor2.pitch) + 4 |
|
|
this.bottom = Math.min(this.anchor1.pitch, this.anchor2.pitch) - 4 |
|
|
} else { |
|
|
this.top = this.anchor2.pitch + 4 |
|
|
this.bottom = this.anchor2.pitch - 4 |
|
|
} |
|
|
}; |
|
|
|
|
|
|
|
|
TieElem.prototype.setStartX = function (startLimitElem) { |
|
|
this.startLimitX = startLimitElem; |
|
|
}; |
|
|
|
|
|
TieElem.prototype.setEndX = function (endLimitElem) { |
|
|
this.endLimitX = endLimitElem; |
|
|
}; |
|
|
|
|
|
TieElem.prototype.setHint = function () { |
|
|
this.hint = true; |
|
|
}; |
|
|
|
|
|
TieElem.prototype.calcTieDirection = function () { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (this.isGrace) |
|
|
this.above = false; |
|
|
else if (this.voiceNumber === 0) |
|
|
this.above = true; |
|
|
else if (this.voiceNumber > 0) |
|
|
this.above = false; |
|
|
else { |
|
|
var referencePitch; |
|
|
if (this.anchor1) |
|
|
referencePitch = this.anchor1.pitch; |
|
|
else if (this.anchor2) |
|
|
referencePitch = this.anchor2.pitch; |
|
|
else |
|
|
referencePitch = 14; |
|
|
|
|
|
if ((this.anchor1 && this.anchor1.stemDir === 'down') && (this.anchor2 && this.anchor2.stemDir === "down")) |
|
|
this.above = true; |
|
|
else if ((this.anchor1 && this.anchor1.stemDir === 'up') && (this.anchor2 && this.anchor2.stemDir === "up")) |
|
|
this.above = false; |
|
|
else if (this.anchor1 && this.anchor2) |
|
|
this.above = referencePitch >= 6; |
|
|
else if (this.anchor1) |
|
|
this.above = this.anchor1.stemDir === "down"; |
|
|
else if (this.anchor2) |
|
|
this.above = this.anchor2.stemDir === "down"; |
|
|
else |
|
|
this.above = referencePitch >= 6; |
|
|
} |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
TieElem.prototype.calcSlurDirection = function () { |
|
|
if (this.isGrace) |
|
|
this.above = false; |
|
|
else if (this.voiceNumber === 0) |
|
|
this.above = true; |
|
|
else if (this.voiceNumber > 0) |
|
|
this.above = false; |
|
|
else { |
|
|
var hasDownStem = false; |
|
|
if (this.anchor1 && this.anchor1.stemDir === "down") |
|
|
hasDownStem = true; |
|
|
if (this.anchor2 && this.anchor2.stemDir === "down") |
|
|
hasDownStem = true; |
|
|
for (var i = 0; i < this.internalNotes.length; i++) { |
|
|
var n = this.internalNotes[i]; |
|
|
if (n.stemDir === "down") |
|
|
hasDownStem = true; |
|
|
} |
|
|
this.above = hasDownStem; |
|
|
} |
|
|
}; |
|
|
|
|
|
TieElem.prototype.calcX = function (lineStartX, lineEndX) { |
|
|
if (this.anchor1) { |
|
|
this.startX = this.anchor1.x; |
|
|
if (this.anchor1.scalex < 1) |
|
|
this.startX -= 3; |
|
|
} else if (this.startLimitX) |
|
|
this.startX = this.startLimitX.x + this.startLimitX.w; |
|
|
else { |
|
|
if (this.anchor2) |
|
|
this.startX = this.anchor2.x - 20; |
|
|
else |
|
|
this.startX = lineStartX; |
|
|
} |
|
|
if (!this.anchor1 && this.dotted) |
|
|
this.startX -= 3; |
|
|
|
|
|
if (this.anchor2) |
|
|
this.endX = this.anchor2.x; |
|
|
else if (this.endLimitX) |
|
|
this.endX = this.endLimitX.x; |
|
|
else |
|
|
this.endX = lineEndX; |
|
|
}; |
|
|
|
|
|
TieElem.prototype.calcTieY = function () { |
|
|
|
|
|
if (this.anchor1) |
|
|
this.startY = this.anchor1.pitch; |
|
|
else if (this.anchor2) |
|
|
this.startY = this.anchor2.pitch; |
|
|
else |
|
|
this.startY = this.above ? 14 : 0; |
|
|
|
|
|
if (this.anchor2) |
|
|
this.endY = this.anchor2.pitch; |
|
|
else if (this.anchor1) |
|
|
this.endY = this.anchor1.pitch; |
|
|
else |
|
|
this.endY = this.above ? 14 : 0; |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
TieElem.prototype.calcSlurY = function () { |
|
|
if (this.anchor1 && this.anchor2) { |
|
|
if (this.above && this.anchor1.stemDir === "up" && !this.fixedY) { |
|
|
this.startY = (this.anchor1.highestVert + this.anchor1.pitch) / 2; |
|
|
this.startX += this.anchor1.w / 2; |
|
|
} else |
|
|
this.startY = this.anchor1.pitch; |
|
|
|
|
|
|
|
|
var beamInterferes = this.anchor2.parent.beam && this.anchor2.parent.beam.stemsUp && this.anchor2.parent.beam.elems[0] !== this.anchor2.parent; |
|
|
var midPoint = (this.anchor2.highestVert + this.anchor2.pitch) / 2; |
|
|
if (this.above && this.anchor2.stemDir === "up" && !this.fixedY && !beamInterferes && (midPoint < this.startY)) { |
|
|
this.endY = midPoint; |
|
|
this.endX += Math.round(this.anchor2.w / 2); |
|
|
} else |
|
|
this.endY = this.above && beamInterferes ? this.anchor2.highestVert : this.anchor2.pitch; |
|
|
|
|
|
if (this.anchor1.scalex === 1) { |
|
|
var hasBeam1 = !!this.anchor1.parent.beam |
|
|
var hasBeam2 = !!this.anchor2.parent.beam |
|
|
if (hasBeam1) { |
|
|
var isLastInBeam = this.anchor1.parent === this.anchor1.parent.beam.elems[this.anchor1.parent.beam.elems.length-1] |
|
|
if (!isLastInBeam) { |
|
|
if (this.above) |
|
|
this.startY = this.anchor1.parent.fixed.t |
|
|
else |
|
|
this.startY = this.anchor1.parent.fixed.b |
|
|
} |
|
|
} |
|
|
|
|
|
if (hasBeam2) { |
|
|
var isFirstInBeam = this.anchor2.parent === this.anchor2.parent.beam.elems[0] |
|
|
if (!isFirstInBeam) { |
|
|
if (this.above) |
|
|
this.endY = this.anchor2.parent.fixed.t |
|
|
else |
|
|
this.endY = this.anchor2.parent.fixed.b |
|
|
} |
|
|
} |
|
|
} |
|
|
} else if (this.anchor1) { |
|
|
this.startY = this.endY = this.anchor1.pitch; |
|
|
} else if (this.anchor2) { |
|
|
this.startY = this.endY = this.anchor2.pitch; |
|
|
} else { |
|
|
|
|
|
|
|
|
this.startY = this.above ? 14 : 0; |
|
|
this.endY = this.above ? 14 : 0; |
|
|
} |
|
|
}; |
|
|
|
|
|
TieElem.prototype.avoidCollisionAbove = function () { |
|
|
|
|
|
if (this.above) { |
|
|
var maxInnerHeight = -50; |
|
|
for (var i = 0; i < this.internalNotes.length; i++) { |
|
|
if (this.internalNotes[i].highestVert > maxInnerHeight) |
|
|
maxInnerHeight = this.internalNotes[i].highestVert; |
|
|
} |
|
|
if (maxInnerHeight > this.startY && maxInnerHeight > this.endY) |
|
|
this.startY = this.endY = maxInnerHeight - 1; |
|
|
} |
|
|
}; |
|
|
|
|
|
TieElem.prototype.getYBounds = function () { |
|
|
var lineStartX = 10 |
|
|
var lineEndX = 1000 |
|
|
if (this.isTie) { |
|
|
this.calcTieDirection(); |
|
|
this.calcX(lineStartX, lineEndX); |
|
|
this.calcTieY(); |
|
|
|
|
|
} else { |
|
|
this.calcSlurDirection(); |
|
|
this.calcX(lineStartX, lineEndX); |
|
|
this.calcSlurY(); |
|
|
} |
|
|
var top; |
|
|
var bottom; |
|
|
|
|
|
if (this.above) { |
|
|
bottom = Math.min(this.startY, this.endY) |
|
|
top = bottom + 3 |
|
|
} else { |
|
|
top = Math.min(this.startY, this.endY) |
|
|
bottom = top - 3 |
|
|
} |
|
|
return [ top, bottom ] |
|
|
}; |
|
|
|
|
|
module.exports = TieElem; |
|
|
|