\version "2.19.45" JSSVGBeamTuner = #(define-void-function (body) (string?) (let* ((mod (resolve-module '(scm framework-svg))) (svg-end (module-ref mod 'svg-end #f))) (if (procedure? svg-end) (module-define! mod 'svg-end (lambda () (string-join (list "" (svg-end)) "\n")))))) JSSVGBeamTunerScript = #" rootNode = document.querySelector('svg') pixelsX = rootNode.getAttribute('width').replace('mm', '') * 96 / 25.4 pixelsY = rootNode.getAttribute('height').replace('mm', '') * 96 / 25.4 scaleX = rootNode.getAttribute('viewBox').split(' ')[2] / pixelsX scaleY = rootNode.getAttribute('viewBox').split(' ')[3] / pixelsY var beamId = 0 var currGrob = null function pointsArrToStr(points) { pointsStr = '' for (var i = 0; i< 8; i++) { pointsStr += points[i] + ' ' } return pointsStr.substring(0, pointsStr.length - 1) } function initBeam(n1) { n1.setAttribute('id', beamId) for (n2 = n1.firstChild; n2 !== null; n2 = n2.nextSibling) { if (n2.nodeName == 'polygon') { //TODO Ugly parsering, replace with a proper and safer one transf = n2.getAttribute('transform') // TODO: check backspaces? // TODO: check if it doesn't have transform attr? translateX = transf.replace('translate(', '').split(',')[0] translateY = transf.split(',')[1].trim().replace(')', '') points = n2.getAttribute('points').split(' ') //alert(translateX) for (var i = 0; i<7; i = i+2) { points[i] = Number(points[i]) + Number(translateX) } for (var i = 1; i<8; i = i+2) { points[i] = Number(points[i]) + Number(translateY) } pointsStr = pointsArrToStr(points) n2.setAttribute('points', pointsStr) n2.setAttribute('origPoints', pointsStr) n2.setAttribute('id', 'lilyBeamPoly_'+beamId) n2.setAttribute('onmousedown', 'selectGrob(this)') n2.removeAttribute('transform') n2.setAttribute('anchor', '') } } beamId++ } function selectGrob(grob) { if (!grob.hasAttribute('id')) return if (!detectLeftButton(event)) { event.preventDefault() showGrobModifyExpr(grob) return } grob.setAttribute('color', 'cyan') points = grob.getAttribute('points').split(' ') leftX = Number(points[4]) rightX = Number(points[0]) distanceFromRightSide = Math.abs(event.pageX * scaleX - rightX) distanceFromLeftSide = Math.abs(event.pageX * scaleX - leftX) distanceFromCenter = Math.abs(event.pageX * scaleX - (leftX + (rightX - leftX)/2)) minDistance = Math.min(distanceFromLeftSide, distanceFromCenter, distanceFromRightSide) switch(minDistance) { case distanceFromRightSide: grob.setAttribute('anchor','right') break; case distanceFromLeftSide: grob.setAttribute('anchor','left') break; case distanceFromCenter: grob.setAttribute('anchor','center') break; } grob.setAttribute('yScreenPrev', event.pageY * scaleY) currGrob = grob } function detectLeftButton(evt) { evt = evt || window.event if ('buttons' in evt) { return evt.buttons == 1 } var button = evt.which || evt.button return button == 1 } function unselectGrob() { if (currGrob) currGrob.setAttribute('color', 'black') currGrob = null } function moveGrob() { if (!currGrob) return points = currGrob.getAttribute('points').split(' ') origPoints = currGrob.getAttribute('origPoints').split(' ') idx1 = 1 idx2 = 8 if (currGrob.getAttribute('anchor') == 'left') { idx1 = 5 } else if (currGrob.getAttribute('anchor') == 'right') { idx2 = 5 } for (var i = idx1; i < idx2; i = i + 2) { points[i] = Number(points[i]) + event.pageY * scaleY - Number(currGrob.getAttribute('yScreenPrev')) } currGrob.setAttribute('yScreenPrev', event.pageY * scaleY) currGrob.setAttribute('points', pointsArrToStr(points)) } window.oncontextmenu = function(evt) { evt.preventDefault() } function showGrobModifyExpr(grob) { angleLeft = +((grob.getAttribute('origPoints').split(' ')[5] - grob.getAttribute('points').split(' ')[5]).toFixed(3)) angleRight = +((grob.getAttribute('origPoints').split(' ')[1] - grob.getAttribute('points').split(' ')[1]).toFixed(3)) lilyExpr = '-\\\\offset positions ' + '#\\'(' + angleLeft + ' . ' + angleRight + ')' alert(lilyExpr) } var as = document.querySelectorAll('a') //Remove all 'a' tags for (var i = 0; i < as.length; i++) { as[i].replaceWith(...as[i].childNodes) } beams = document.querySelectorAll('svg .lilyBeam') for (var i = 0; i < beams.length; i++) { initBeam(beams[i]) } document.addEventListener('mouseup', unselectGrob) document.addEventListener('mousemove', moveGrob) " addJSSVGBeamTuner = \JSSVGBeamTuner \JSSVGBeamTunerScript addSVGBeamHandler = { \override Beam.output-attributes = #'((class . "lilyBeam")) } \score { { \addSVGBeamHandler % How-to: % 1) move with the left mouse button the angles or the vertical position % of the beam in the SVG output file. % 2) right-click and replace the line below with the output string in this way: % a8-\offset positions #'(y1 . y2)[ c' c' c'] c' d' e' f' a8[ c' c' c'] c'[ d' e' f'] c'''[ e''' c''' c'''] c'''[ e''' c''' c'''] } } \addJSSVGBeamTuner