Public
Edited
Sep 5, 2023
2 forks
Importers
2 stars
Insert cell
Insert cell
vis = html`<div class="vis-cc"></div>`
Insert cell
waffle(value, {
bind: d3.select(vis), // pass in the selection
activeFill: '#3dbd5d'
})
Insert cell
Insert cell
visSquare = html`<div class="vis-cc-square"></div>`
Insert cell
waffle(value, {
bind: d3.select(visSquare), // pass in the selection
activeFill: '#de4500',
passiveFill: '#ebd999',
shape: 'rect'
})
Insert cell
function waffle (value = 90, {
bind = null, // pass in a d3 selection i.e d3.select('class/div')
shape = 'circle', // 'circle' 'rect'
activeFill = '#008cbc', // colour of the square or circle
passiveFill = '#e5e7de', // when there is no value
strokeCol = '#666666',
shapeSize = 15,
strokeWidth = 0,
margin = {
top: shapeSize,
right: shapeSize,
bottom: shapeSize,
left: shapeSize,
}
} = {}) {

const size = (shapeSize + (strokeWidth * 2)) * 10

// append the svg if first render
if (bind.select('svg').empty()) {
bind
.append('svg')
.attr('width', size + margin.left + margin.right)
.attr('height', size + margin.top + margin.bottom)
.append('g')
.attr('transform', `translate(${margin.left}, ${margin.top})`)
.call(grid10by10)
}

function grid10by10 (sel) {
const scaleX = d3.scaleLinear()
.domain([0, 9])
.range([0, shapeSize * 10])

const scaleY = d3.scaleLinear()
.domain([0, 9])
.range([shapeSize * 10, 0])

const render = sel.selectAll(shape)
.data(d3.range(100))
.join(shape)
.attr('stroke-width', strokeWidth)
.attr('stroke', strokeCol)
// note < not <= as counting from 0
.attr('fill', (d, i) => (i < value) ? activeFill : passiveFill)

if (shape === 'rect') {
render
.attr('x', (d, i) => {
const n = i % 10
return scaleX(n)
})
.attr('y', (d, i) => {
const n = Math.floor(i / 10)
return scaleY(n)
})
.attr('width', shapeSize)
.attr('height', shapeSize)
} else {
render
.attr('cx', (d, i) => {
const n = i % 10
return scaleX(n)
})
.attr('cy', (d, i) => {
const n = Math.floor(i / 10)
return scaleY(n)
}).attr('r', shapeSize / 2)
}
}

return bind.select('svg g').call(grid10by10)

}
Insert cell
Insert cell
Insert cell
visWrap = html`<div class="vis-1 flex flex-wrap "></div>`
Insert cell
{ // have a way of updating the cell put not creating extra dom elements
if (d3.select(visWrap).empty()) { // don't reload on any cell refreshes
testMultipleRender(visWrap);
} else {
d3.select(visWrap).selectAll('div').remove();
testMultipleRender(visWrap);
}
}
Insert cell
viewof activeFill = Inputs.color({label: "Active fill:", value: "#505423"})
Insert cell
viewof passiveFill = Inputs.color({label: "Passive fill:", value: "#eeeeee"})
Insert cell
function testMultipleRender(sel, col) { // render dom and bind svg visual to it
return [30, 45, 25, 80, 60, 5, 20, 25, 15, 10, 90, 50].forEach((d, i) => {
const div = d3.select(visWrap).append('div').attr('class', 'ref-' + i)
d3.select('.ref-' + i).selectAll('h3').remove(); // tidy for refreshes on page
d3.select('.ref-' + i).append('h3').attr('class', 'label').text(d + '%')
waffle(d, {
bind: d3.select('.ref-' + i),
activeFill: activeFill,
passiveFill: passiveFill,
})
})
}
Insert cell
<hr>
<link href="https://fonts.googleapis.com/css?family=Space+Mono" rel="stylesheet">
<link href="https://unpkg.com/basscss@8.0.2/css/basscss.min.css" rel="stylesheet">
<style>
.label {
font-family:'Space Mono',monospace;
color: #008cbc;
font-size: 13px;
padding-left: 5px;
}
</style>
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more