Public
Edited
Dec 4, 2023
Paused
1 star
Insert cell
Insert cell
What's up <x-mark orange>doc</x-mark>? This is a test <x-mark>boodle</x-mark> <x-mark class="green">boodle doodle this is a longer one</x-mark> and then some more text. <x-mark>Boodle boodle doodle this is an even longer one</x-mark> and then some <x-mark pink>more text</x-mark>. <x-mark blue>Boodle boodle longer one</x-mark> and then some more text. <x-mark>Boodle boodle doodle this is a much longer one this is a much longer one this is a much longer one this is a much longer one this is a much longer one</x-mark> and then some more text. Then some more text. Then some more text. Then some more text. Then some more text. Then some more text. Then some more text. <x-mark pink>Boodle doodle doodle</x-mark>.
Insert cell
Insert cell
<style>
x-mark[blue] {
--color: rgb(0,200,255);
}
x-mark[orange] {
--color: rgb(255,170,0);
}
x-mark.green {
--color: rgb(0,255,0);
}
x-mark[pink] {
--color: rgb(255,0,170);
}
</style>
Insert cell
makeCustomHighlighterTag("x-mark")
Insert cell
function makeCustomHighlighterTag(
tagName = "x-mark",
defaultColor = "rgb(255,255,0)"
) {
class HighlighterStyleElement extends HTMLElement {
connectedCallback() {
this.attachShadow({ mode: "open" });
let hPadding = 0.25;
let vPadding = 0.15;
let hOffset = (2 * Math.random() - 1) * hPadding;
let vOffset = (2 * Math.random() - 1) * vPadding;
let minAngle = Math.max(90 - this.textContent.length / 1.5, 20);
let maxAngle = Math.min(minAngle + 20, 90);
let angle = minAngle + (maxAngle - minAngle) * Math.random();
let top = vPadding + vOffset;
let bottom = vPadding - vOffset;
let left = hPadding - hOffset;
let right = hPadding + hOffset;
this.shadowRoot.innerHTML = `
<style>
:host {
--color: ${defaultColor};
}
mark {
margin: ${-top}em ${-right}em ${-bottom}em ${-left}em;
padding: ${top}em ${right}em ${bottom}em ${left}em;
border-radius: 0.5em 0.3em;
background: transparent;
box-decoration-break: clone;
-webkit-box-decoration-break: clone;
background-image: linear-gradient(
${angle}deg,
color-mix(in srgb, var(--color), transparent 50%),
color-mix(in srgb, var(--color), transparent 90%) 4%,
color-mix(in srgb, var(--color), transparent 70%) 96%,
color-mix(in srgb, var(--color), transparent 30%)
);
}
</style>
<mark>${this.textContent}</mark>
`;
}
}

customElements.get(tagName) ||
customElements.define(tagName, HighlighterStyleElement);

return html`<span style="color:grey;"><span style="font:var(--monospace-font);">&lt;${tagName}&gt;</span> is defined for highlighter-type styles. Use <span style="font:var(--monospace-font);">${tagName} {--color: ...};</span> to style.</span>`;
}
Insert cell
I think I might like having a custom tag (<x-mark pink>like this</x-mark>) rather than a function ${marked("like this", "pink")} but it's pretty similar. The component has the downside that I don't think there's any way to "de-register" the name, so once it's defined it takes a hard refresh to change it.
Insert cell
<style>
mark.pink {
--color: rgb(255,0,170);
}
</style>
Insert cell
function marked(text, cls = "", defaultColor = "rgb(255,255,0)") {
return html`<mark class="${cls}" --color: ${defaultColor}; style="${makeStyle(
text
)}">${text}</mark>`;
}
Insert cell
function makeStyle(text) {
let hPadding = 0.25;
let vPadding = 0.15;
let hOffset = (2 * Math.random() - 1) * hPadding;
let vOffset = (2 * Math.random() - 1) * vPadding;
let minAngle = Math.max(90 - text.length / 1.5, 20);
let maxAngle = Math.min(minAngle + 20, 90);
let angle = minAngle + (maxAngle - minAngle) * Math.random();
let top = vPadding + vOffset;
let bottom = vPadding - vOffset;
let left = hPadding - hOffset;
let right = hPadding + hOffset;
let raw = `margin: ${-top}em ${-right}em ${-bottom}em ${-left}em;
padding: ${top}em ${right}em ${bottom}em ${left}em;
border-radius: 0.5em 0.3em;
background: transparent;
box-decoration-break: clone;
-webkit-box-decoration-break: clone;
background-image: linear-gradient(
${angle}deg,
color-mix(in srgb, var(--color), transparent 50%),
color-mix(in srgb, var(--color), transparent 90%) 4%,
color-mix(in srgb, var(--color), transparent 70%) 96%,
color-mix(in srgb, var(--color), transparent 30%)
);`;
return raw.split(/\s+/).join(" ");
}
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