Here's the fixed version:

waiting for feedbacks!

(Again and again: I write these snippets really in a hurry, in these days.
A more "structured" collaboration is getting necessary for me, at this
point)

Any Javascript volunteer?


On Tue, Dec 17, 2019 at 1:24 AM Paolo Prete <[email protected]> wrote:

> I'm just noting that there's a bug with more than one Beam. I'm fixing it.
> Have a bit of patience please ;-)
>
> On Mon, Dec 16, 2019 at 11:55 PM Paolo Prete <[email protected]> wrote:
>
>> Hello everybody,
>>
>> here is another snippet that uses the system that I previously
>> implemented. This time for the tuning of the beams.
>> This is too a very tedious operation to do with just the code and for
>> this I believe that this tool is also useful.
>> As you can see, the code is not only shorter than the previous one, but
>> it recycles the whole template of the previous snippet, which I'm making
>> more and more generic.
>> In short, the goal is to have Lilypond itself automatically create a GUI
>> tool for the tuning of the main properties of the grobs.
>>
>> This is somewhat crazy: Lilypond used as a factory for WYSIWYG editors!
>> :-)
>>
>> HTH
>>
>> Paolo
>>
>> P.S) I don't know why the browser's viewer messes up the indentation of
>> these attachments.
>> If so, I ask if are there volunteers to fix that and re-post the snippet
>> (I see correct indentation if I paste the code to any online js editor)
>>
>>
\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 "<script type=\"text/javascript\"><![CDATA["
               body "]]></script>" (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

Reply via email to