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

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more