Published
Edited
Oct 2, 2020
1 star
Insert cell
Insert cell
Insert cell
data = {
const regions = d3
.hierarchy(rawData)
.sum(d => 1)
.sort((a, b) => b.value - a.value);

const pack = d3
.pack()
.size([474, 488])
.padding(3);

return pack(regions);
}
Insert cell
Insert cell
canvas = {
div; // wait for DOM to load
// clean slate
document.querySelector('.canvas').innerHTML = '';
// append canvas
document
.querySelector('.canvas')
.appendChild(document.createElement('h2')).textContent = '<canvas />';
const title = document
.querySelector('.canvas')
.appendChild(document.createElement('h1'));
const canvas = document
.querySelector('.canvas')
.appendChild(document.createElement('canvas'));
canvas.width = 474;
canvas.height = 488;

const context = canvas.getContext('2d');
const TAU = 2 * Math.PI;

function draw(
ctx,
node,
{ fillStyle = 'rgba(0, 0, 0, 0.2)', textColor = 'white' } = {},
checkCollision
) {
const children = node.children;
const { x, y, r } = node;
ctx.fillStyle = fillStyle;
ctx.beginPath();
ctx.arc(x, y, r, 0, TAU);
if (checkCollision) {
var { mx, my } = checkCollision;
if (ctx.isPointInPath(mx, my)) {
ctx.fillStyle = 'rgba(0, 128, 0, 0.1)';
title.textContent = node.data.name;
}
}
ctx.fill();
ctx.closePath();

if (children) {
for (let i = 0; i < children.length; i++) {
draw(context, children[i], {}, { mx, my });
}
} else {
const name = node.data.name;
ctx.fillStyle = textColor;
ctx.font = '8px Arial';
ctx.textAlign = 'center';
ctx.fillText(name, x, y);
}
}

draw(context, data);

canvas.onmousemove = function(e) {
let rect = this.getBoundingClientRect(),
mx = e.clientX - rect.left,
my = e.clientY - rect.top;

context.clearRect(0, 0, canvas.width, canvas.height);
draw(context, data, {}, { mx, my });
};
}
Insert cell
svg = {
div; // wait for DOM to load
// clean slate
document.querySelector('.svg').innerHTML = '';
document
.querySelector('.svg')
.appendChild(document.createElement('h2')).textContent = '<svg />';
// append svg
const svg = document
.querySelector('.svg')
.appendChild(document.createElementNS("http://www.w3.org/2000/svg", 'svg'));
svg.setAttribute('viewBox', '0 0 474 488');
const title = document
.querySelector('.svg')
.appendChild(document.createElement('h1'));

function draw(
parent,
node,
{ fillStyle = 'rgba(0, 0, 0, 0.2)', textColor = 'white' } = {}
) {
const children = node.children;
const { x, y, r } = node;
const circle = document.createElementNS(
'http://www.w3.org/2000/svg',
'circle'
);
circle.setAttribute('cx', x);
circle.setAttribute('cy', y);
circle.setAttribute('r', r);
circle.setAttribute('fill', fillStyle);
circle.setAttribute('data-name', node.data.name);
parent.appendChild(circle);
if (children) {
const group = document.createElementNS('http://www.w3.org/2000/svg', 'g');
for (let i = 0; i < children.length; i++) {
draw(group, children[i], { fillStyle, textColor });
}
group.setAttribute('data-name', node.data.name);
parent.appendChild(group);
} else {
const text = document.createElementNS(
'http://www.w3.org/2000/svg',
'text'
);
text.setAttribute('fill', textColor);
text.setAttribute('font-family', 'Arial');
text.setAttribute('font-size', '8px');
text.setAttribute('text-anchor', 'middle');
text.setAttribute('x', x);
text.setAttribute('y', y);
const name = node.data.name;
text.textContent = name;
parent.appendChild(text);
}
}

draw(svg, data);

function getTitleText(target) {
const name = target.getAttribute('data-name');
if (target.parentNode && target.parentNode.nodeName === 'g') {
const parentName = target.parentNode.getAttribute('data-name');
return `${parentName}-${name}`;
}
return name;
}

let activeTarget = null;
svg.addEventListener('mousemove', evt => {
let target = evt.target;
if (target.nodeName === 'text') target = target.previousSibling;
if (activeTarget !== target) {
if (activeTarget) activeTarget.setAttribute('fill', 'rgba(0, 0, 0, 0.2)');
}
target.setAttribute('fill', 'rgba(0, 128, 0, 0.1)');
title.textContent = getTitleText(target);
activeTarget = target;
});
}
Insert cell
Insert cell
triangle = {
const height = width / 2;
const ctx = DOM.context2d(width, height);

ctx.beginPath();
ctx.moveTo(width / 2, height / 2);
ctx.lineTo(width / 2 - 50, height / 2 + 50);
ctx.lineTo(width / 2 + 50, height / 2 + 50);
ctx.fillStyle = 'orange';
ctx.fill();
ctx.closePath();
ctx.stroke();

return ctx.canvas;
}
Insert cell
ellipse = {
const height = width / 2;
const ctx = DOM.context2d(width, height);

ctx.beginPath();
ctx.ellipse(width / 2, height / 2, 50, 75, Math.PI / 4, 0, 2 * Math.PI);
ctx.fillStyle = 'yellow';
ctx.fill();
ctx.stroke();

return ctx.canvas;
}
Insert cell
star = {
const height = width / 2;
const ctx = DOM.context2d(width, height);

drawStar(ctx, width / 2, height / 2, 5, 100, 40);

return ctx.canvas;
}
Insert cell
function drawStar(ctx, cx, cy, spikes, outerRadius, innerRadius) {
let rot = (Math.PI / 2) * 3;
let x = cx;
let y = cy;
const step = Math.PI / spikes;

ctx.beginPath();
ctx.moveTo(cx, cy - outerRadius);
for (let i = 0; i < spikes; i++) {
x = cx + Math.cos(rot) * outerRadius;
y = cy + Math.sin(rot) * outerRadius;
ctx.lineTo(x, y);
rot += step;

x = cx + Math.cos(rot) * innerRadius;
y = cy + Math.sin(rot) * innerRadius;
ctx.lineTo(x, y);
rot += step;
}
ctx.lineTo(cx, cy - outerRadius);
ctx.closePath();
ctx.lineWidth = 2;
ctx.strokeStyle = 'blue';
ctx.stroke();
ctx.fillStyle = 'skyblue';
ctx.fill();
}
Insert cell
style = html`
<style>
.root {
border: 1px solid black;
display: flex;
}
.canvas {
border: 1px solid green;
width: 50%;
position: relative;
}
.svg {
border: 1px solid blue;
width: 50%;
position: relative;
}
.root canvas, .root svg {
width: 100%;
height: 100%;
}
.svg h1 {
position: absolute;
top: 0;
right: 0;
font-size: 12px;
color: grey;
}
.canvas h2, .svg h2 {
position: absolute;
top: 0;
left: 0;
font-size: 10px;
}
.canvas h1 {
position: absolute;
top: 0;
right: 0;
font-size: 12px;
color: grey;
}
</style>
`
Insert cell
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