DEV Community

Cover image for Josef Müller-Brockmann poster
Jim Montgomery
Jim Montgomery

Posted on

Josef Müller-Brockmann poster

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>
Enter fullscreen mode Exit fullscreen mode

Top comments (0)