Jim Montgomery
Posted on February 18, 2022
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>
💖 💪 🙅 🚩
Jim Montgomery
Posted on February 18, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.