DEV Community

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

Posted on

5 2

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

Speedy emails, satisfied customers

Postmark Image

Are delayed transactional emails costing you user satisfaction? Postmark delivers your emails almost instantly, keeping your customers happy and connected.

Sign up

Top comments (0)

AWS Security LIVE!

Tune in for AWS Security LIVE!

Join AWS Security LIVE! for expert insights and actionable tips to protect your organization and keep security teams prepared.

Learn More

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay