Josef Müller-Brockmann poster
Tags: svg, design
Published: 2022-02-18 12:38:08

tooling around with svg to share my appreciation for Swiss Style, modern design history and catch up with a little tech: https://www.jimmont.com/art/beethoven.html

the interaction and viewport dynamic made for a fun exploration into how the original was made and looks in a new context

more about the original designer Josef https://en.wikipedia.org/wiki/Josef_M%C3%BCller-Brockmann

the svg excerpt:
```
<svg viewBox="0 0 750 1076" version="1.1" style="width:100vw;height:100vh;">
<title>Josef Müller-Brockmann 1955 Beethoven poster</title>
<!-- remembering
Josef Müller-Brockmann
https://en.wikipedia.org/wiki/Josef_Muller-Brockmann
1955 Beethoven poster
-->
<style>
svg{background-color:#000;overflow:visible;}
:root{
	--circle: rgba(255,255,255,1);
	--pie: rgba(0,0,0,1);
	--stroke: #fff;
	--stroke-width: 3px;
}
text,tspan{font-family:arial,sans-serif;font-size: 11px; word-spacing: 0px;line-height:1.1;line-height: 1.1; white-space: pre; text-anchor:start;}
.align-right, .align-right *{text-anchor:end;}
#beethoven{font-size: 32px; font-weight: 700; line-height: 1;}

circle{fill:var(--circle, #fff);stroke:var(--stroke, #fff);stroke-width:var(--stroke-width);}
g.group{
	transform:rotate(0deg);
	transition:transform 3s;
}
g.group.on{
	/* transform:rotate(360deg); */
	animation: 3s rotations ease-in-out;
}
@keyframes rotations{
	0% {transform:rotate(0);}
	45% {transform:rotate(360deg);}
	90% {transform:rotate(0);}
	100% {}
}

path{fill:var(--pie, #000);stroke:var(--stroke, #fff);stroke-width:var(--stroke-width);}
#topdisc{fill:var(--pie, #fff);}
</style>

<g style="transform:translate(203px, 770px);" id="discs">

<rect width="60" height="60" bx:origin="0 0" fill="rgba(255,255,255,0.3)"/>
</g>

<g style="transform:translate(198px, 781px);" id="texts">
<g class="group">
<text class="align-right" id="beethoven" x="0" y="-78">beethoven</text>

<text class="align-right" id="left-labels" x="0" y="0">
<tspan x="0">tonhalle</tspan>
<tspan x="0" dy="6.6em">leitung</tspan>
<tspan x="0" dy="1.2em">solist</tspan>
<tspan x="0" dy="1.8em">beethoven</tspan>
<tspan x="0" dy="4.2em">vorverkauf</tspan>
</text>

<text x="4" y="0">
<tspan x="4">grosser saal</tspan>
<tspan x="4" dy="1.2em">dienstag, den 22, februar 1955,</tspan>
<tspan x="4" dy="1.2em">20.15 uhr</tspan>
<tspan x="4" dy="1.2em">4. extrakonzert</tspan>
<tspan x="4" dy="1.2em">der tonhalle-gesellschaft</tspan>
<tspan x="4" dy="1.8em">carl schuricht</tspan>
<tspan x="4" dy="1.2em">wolfgang schneiderhan</tspan>
<tspan x="4" dy="1.8em">ouverture zu -coriolan-,op. 62</tspan>
<tspan x="4" dy="1.2em">violinkonzert in d-dur,op. 61</tspan>
<tspan x="4" dy="1.2em">siebente sinfonie in a-dur,op. 92</tspan>
<tspan x="4" dy="1.8em">tonhalle-kasse, hug, jecklin,</tspan>
<tspan x="4" dy="1.2em">kuoni</tspan>
<tspan x="4" dy="1.2em">karten zu fr.3.50 bis 9.50</tspan>
<tspan x="4" dy="1.2em"/>
</text>
</g>
</g>
<script>
// <![CDATA[

// circle divided in 32 parts, 2π
const angleIncrement = 2*Math.PI/32;
// series x2, 1-32 => 1, 2, 4, 8, 16, 32
// dr = (end - start) / 32 = (900-260)/32 = 20;
// see from looking at the image and calculation output the added space for each circle's border
// visually approximated small and large circles
// step small number to find a reasonable value, step larger one to find value /32 where it yields at whole number
// account for the offset, notice 1px border
// radius is dr * step + sum of 1 unit borders, so index * 1px border;
// radius = step * dr + i;
const dr = 10;

let arc, arcs, arclist = [
	[], // text in first
	// [start-unit, size]
	[[-2,5], [12,5]], 		// 5, -9, 5 @1
	[[-4, 6], [8, 6]],		// 6, -6, 6 @2
	[[-7, 8], [4,12]], 		// 7, -4, 8+? @4
	[[-8,25]], 			// 20+??, -? ? @8
	[[-4, 22]], 			// ? @16
	[[-9, 20]]  			// ? @32
];

let i = 0
, step = 1
, parent = document.querySelector('#discs')
, r0 = 250 //c0.getBBox().width / 2
, circle = parent.ownerDocument.createElementNS('http://www.w3.org/2000/svg', 'circle')
, path = parent.ownerDocument.createElementNS('http://www.w3.org/2000/svg', 'path')
, group = parent.ownerDocument.createElementNS('http://www.w3.org/2000/svg', 'g')
, copy, g, off
, radius
;
group.classList.add('group');
function onpath(event){
	let node = event.composedPath().find(node=>node.matches&&node.matches('g.group'));
	if(!node) return;
	if(node.matches('path')) node = node.parentNode;

	const is = 'on';

	switch(event.type){
	case 'animationend':
		node.classList.remove(is);
	break;
	case 'transitionend':
		node.classList.remove(is);
	break;
	default:
		node.classList.add(is);
	}
}
function rotatable(node){
	'touchmove, touchstart, mouseover, mousedown, transitionend, animationend'.split(/[,\s]+/).forEach(event=>node.addEventListener(event, onpath));
};
rotatable(parent);
rotatable(document.querySelector('#texts'));
while(i < 7){
	off = i * 2;
	radius = r0 + (dr * step) + off;
	console.log(i, step, radius, `${r0}+${step * dr} +${off}`);
	arcs = arclist[ i ];
	let j = 0;
	while(arc = arcs[j++]){
		g = group.cloneNode(true);
		copy = path.cloneNode();
		copy.style.setProperty('d', dpath({radius, angleIncrement, arc}));
		//copy.setAttributeNS('http://www.w3.org/2000/svg', 'd', dpath({radius, angleIncrement, arc}));
		copy.setAttributeNS(null, 'd', dpath({radius, angleIncrement, arc}));
		g.setAttribute('id', `arc${i}-${j}`);
		g.append(copy);
		parent.prepend(g);
	}

	copy = circle.cloneNode();
	copy.setAttribute('id', `c${i}`);
	copy.setAttribute('r', radius);
	parent.prepend(copy);

	step *= 2;
	i++;
}
// arc = [start-relative-to-zero, size-in-angleIncrements];
function dpath({radius, angleIncrement, arc}){

	let a0, x0, y0, a1, x1, y1;
	const [start, size] = arc;
	a0 = angleIncrement * start;
	a1 = a0 + (angleIncrement * size);
	x0 = (Math.cos(a0) * radius);
	y0 = (Math.sin(a0) * radius);
	x1 = (Math.cos(a1) * radius);
	y1 = (Math.sin(a1) * radius);

	const largeArc = Math.abs(a1 - a0) > Math.PI ? 1 : 0;

	return `M0,0 L${x0},${y0} A${radius} ${radius} 0 ${ largeArc } 1 ${x1} ${y1} Z`;

	// Safari doesn't work with CSS d:path(...)
//	return `path('M0,0 L${x0},${y0} A${radius} ${radius} 0 ${ largeArc } 1 ${x1} ${y1} Z')`;
}

// ]]>
</script>
</svg>
```