MediaWiki:LeadingAndTrailingCells.js

let div = (a,b) => Math.floor(a/b);

const sc = 0.7; let svg = d3.select('.LeadingAndTrailingCells') .append('svg').attrs({height:820*sc, width:620*sc}) .append('g') .attr('transform',`scale(${sc})`) .attr('font-size',46) .attr('text-anchor','middle'); let w = 60, h = 58, boxPad = 5, xp = 3;

let shape = [3,3,4], rank = shape.length, dat = [0,0,1,0,1,1,0,0,1,1,1,0,0,0,0,0,0,0,0,1,0,0,1,0,1,0,1,1,0,0,1,0,1,1,1,0]; function getPos(i) { let a = rank-1; let pos = [div(i,shape[a]), i%shape[a]]; a--; let y = pos[0]; while (a--) { y=div(y,shape[a]); pos[0]+=y; } return {x:w*pos[1], y:h*pos[0]}; }

let Wo= w/2+10, W = (shape[rank-1]-1)*w, Wg= 180, H = (shape[0]*(1+shape[1])-1)*h; let gs = svg.selectAll.data(['Trailing','Leading']).enter .append('g').attr('transform',(_,i)=>`translate(${Wo+(W+Wg)*i},70)`); gs.append('rect').attrs({x:-w/2,y:0,width:W+w,height:H,fill:'white'}); gs.append('text').text(t=>t).attrs({ x:W/2, y:-40, 'font-size':40, fill:'#6b6560' }); gs.attr('stroke-width',3);

let getColor = i => d3.hsl(d3.interpolateViridis(0.9-0.25*i)); function getColors(i) { let c = getColor(i); c.s+=0.2; c.l-=0.05; let f = d3.hsl(c); f.l=0.96; return {s:c,f:f}; } function getRect(i,j,dim) { let t = boxPad*i, c = getColors(i), xp= 3; return { x:-t-w/2+xp, width: w*dim[0]+2*(t-xp), y:-t+4*h*j, height:h*dim[1]+2*t, stroke:c.s, fill:c.f   }; }

let trail = gs.filter((_,i)=>i===0) .selectAll.data(d3.range(rank).reverse).enter .append('rect').attrs(i => {      let dim = [1,1];       d3.range(i).forEach(j=>dim[j]=shape[rank-1-j]);       return getRect(i,0,dim);    });

let lead = gs.filter((_,i)=>i===1).selectAll .data(d3.range(rank).reverse).enter .append('g'); lead.selectAll.data(i => {      let dim = [1,1];       if (i>1) dim[1]=shape[rank-2];       return d3.range(i>0?3:1).map(j=>getRect(i,j,dim));    }).enter .append('rect').attrs(a=>a);

gs.selectAll.data(dat).enter .append('text').text(b=>b) .attrs((b,i)=>{let p=getPos(i); p.y+=h-13; return p;});

let iw = w*1.16, iH = H+h+32; indg = gs.append('g').attr('transform',`translate(${(w-iw)*rank/2},0)`) .selectAll.data((_,j)=>shape.map(_=>j)).enter; let inds = indg.append('text').text('1') .attrs((j,i)=>({x:(i+1/2)*iw, y:iH, 'font-size':42, 'font-weight':'bold', fill:'#444'/*getColors(j?i:rank-1-i).s.darker(0.2)*/})); indg.selectAll.data((j,i)=>{       i%=rank;        let c = getColor(i);        c.l = 1 - (1-c.l)*0.8; c.s*=0.86;        let y = iH+8+4*i,            dy= -44-8*i,            sw= [5,3],            ir= rank-i;        return [            [0, 0 , ir],            [ir, 0 , dy],            [ir, dy, i ]        ].map((r,i) => { let h = i!==1, p = ['M',' ',h?'h':'v'], mulh = m => { r[0]*=m; if (h) r[2]*=m; }; if (j) r[0]-=rank; r[1]+=y; mulh(iw); r[2-i] += (i-1)*(sw[0]-sw[1]); if (i===2) r[2]+=18; if (j) mulh(-1); return { d:d3.merge(d3.zip(p,r)).join(''), stroke:c, 'stroke-width':sw[+(i===1)] };       });    }).enter .append('path') .attrs({ fill:'none', 'stroke-linecap':'round', 'stroke-linejoin':'round' }) .attrs(a=>a) .filter((_,i)=>i==2).lower;

gs.on('mousemove', function {    let m = d3.mouse(this);    let x = div(m[0]+w/2,w),        y = div(m[1]    ,h),        s0= 1+shape[0],        b = y%s0,        c = div(y,s0);    if (x<0||x>=shape[rank-1] || b>=shape[0] || c<0||c>=shape[1]) return;    inds.data([c,b,x]).text(i=>i+1);    x*=w; c*=s0;    let s = b+c,        yt= [s,s,c],        yl= [s,b,0];    trail.attr('transform', i=>`translate(${(i?0:x)},${h*yt[i]})`);    lead .attr('transform', i=>`translate(${     x },${h*yl[i]})`); });