Public
Edited
Feb 6
Insert cell
Insert cell
demo = {
const height = 300;
const tooltip = new Tooltip();
return html`<svg viewBox="0 0 ${width} ${height}">
<g fill="none" pointer-events="all" style="cursor:pointer">
${Object.assign(
svg`<rect x="0" height="${height}" width="${width}" stroke="black"></rect>`,
{
ontouchstart: event => event.preventDefault(),
onpointerenter: () => tooltip.show("Wana Hijau Semesta", tooltipKeyValue("VOLUME (TONNES)", "36k")),
onpointermove: event => tooltip.position(...tooltipOffset(tooltip, [event.layerX, event.layerY], width, height)),
onpointerleave: () => tooltip.hide()
}
)}
</g>
${tooltip.node}
</svg>`;
}
Insert cell
class Tooltip {
constructor() {
const dropShadowId = DOM.uid("dropShadow");
const dropShadow = svg`<filter id="${dropShadowId.id}" x="-50%" y="-50%" width="200%" height="200%">
<feDropShadow dx="0" dy="2" stdDeviation="2" flood-opacity="0.5"/>
</filter>`;
const gradientId = DOM.uid("gradient");
const gradient = svg`<linearGradient id="${gradientId.id}" x1="0%" x2="0%" y1="0%" y2="100%">
<stop offset="0%" stop-color="#ddfdef"/>
<stop offset="100%" stop-color="#fff"/>
</linearGradient>`;
this._padding = 12;
this._title = svg`<text x="${this._padding}" y="${this._padding}" dominant-baseline="hanging" font-family="var(--trase-sans-serif)" font-size="15px" font-weight="700" fill="#31464e"></text>`;
this._gradientRect = svg`<rect x="0" y="0" height="60" fill="${gradientId}" ></rect>`;
this._content = svg`<g transform="translate(${this._padding}, ${this._padding * 2 + 28})" font-family="var(--trase-mono)"></g>`;
this._contentRect = svg`<rect x="0" y="0" fill="#fff" filter="${dropShadowId}"></rect>`;
this.node = svg`<g id="tooltip" pointer-events="none" display="none">
<defs>${fonts}${dropShadow}${gradient}</defs>
${this._contentRect}
${this._gradientRect}
${this._title}
${this._content}
</g>`;
}
show(title, content) {
// remove existing attributes
this.node.removeAttribute("display");
this._content.innerHTML = "";
this._contentRect.removeAttribute("height");
this._contentRect.removeAttribute("width");
this._gradientRect.removeAttribute("width");
// add tooltip title and content
this._title.textContent = title;
this._content.appendChild(content);
// resize to accomodate content
const bbox = this.node.getBBox();
this._gradientRect.setAttribute("width", bbox.width + this._padding * 2);
this._gradientRect.setAttribute("height", Math.min(bbox.height + this._padding * 2, 60));
this._contentRect.setAttribute("width", bbox.width + this._padding * 2);
this._contentRect.setAttribute("height", bbox.height + this._padding * 2);
}
position(x, y) {
this.node.setAttribute("transform", `translate(${x},${y})`);
}
hide() {
this.node.setAttribute("display", "none");
}
get width() {
return this.node.getBBox().width;
}
get height() {
return this.node.getBBox().height;
}
}
Insert cell
tooltipKeyValue = (key, value) => svg`<text>
<tspan font-size="10px" fill="#839095" x="0" dy="0em" style="text-transform:uppercase">${key}</tspan>
<tspan font-family="var(--trase-sans-serif)" font-size="14px" font-weight="700" fill="#31464e">${value}</tspan>
<tspan font-size="10px" fill="#839095" x="0" dy="1.5em" style="text-transform:uppercase">${key}</tspan>
<tspan font-family="var(--trase-sans-serif)" font-size="14px" font-weight="700" fill="#31464e">${value}</tspan>
</text>`
Insert cell
tooltipOffset = (tooltip, pointer, width, height, margin) => {
let [x, y] = pointer;
x += 16, y += 8;
if (x + tooltip.width > width) x -= tooltip.width + 24;
if (y + tooltip.height > height) y = height - tooltip.height - 12;
return [x, y];
}
Insert cell
fonts = `<style>
@import url("https://fonts.googleapis.com/css2?family=DM+Sans:wght@700&family=Space+Mono:wght@400&display=swap");
:root{
--trase-mono: "Space Mono", monospace;
--trase-sans-serif: "DM Sans", sans-serif;
}
</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