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)

An Animated Guide to Node.js Event Loop

Node.js doesn’t stop from running other operations because of Libuv, a C++ library responsible for the event loop and asynchronously handling tasks such as network requests, DNS resolution, file system operations, data encryption, etc.

What happens under the hood when Node.js works on tasks such as database queries? We will explore it by following this piece of code step by step.