Skip to content

Instantly share code, notes, and snippets.

@d4hines
Last active July 26, 2023 07:04
Show Gist options
  • Save d4hines/81bca224fd6ec77e59c4c5272a84c448 to your computer and use it in GitHub Desktop.
Save d4hines/81bca224fd6ec77e59c4c5272a84c448 to your computer and use it in GitHub Desktop.
Hill charts in Roam
var old = document.getElementById("hill-chart");
if (old) {
old.remove();
}
var s = document.createElement("script");
s.src = "https://unpkg.com/hill-chart@latest/dist/umd/hill-chart.umd.js";
s.id = "hill-chart";
s.async = true;
s.type = "text/javascript";
document.getElementsByTagName("head")[0].appendChild(s);
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
function getPage(page) {
// returns the uid of a specific page in your graph.
// _page_: the title of the page.
let results = window.roamAlphaAPI.q(`
[:find ?uid
:in $ ?title
:where
[?page :node/title ?title]
[?page :block/uid ?uid]
]`, page);
if (results.length) {
return results[0][0];
}
}
async function getOrCreatePage(page) {
// returns the uid of a specific page in your graph, creating it first if it does not already exist.
// _page_: the title of the page.
try {
roamAlphaAPI.createPage({page: {title: page}});
} catch(e){
// noop
}
let result;
while (!result) {
await sleep(25);
result = getPage(page);
}
return result;
}
function Main(...args){
const [attached, setAttached] = React.useState(false);
const blockUID = args[0].args[0]["block-uid"];
const id = `hill-chart-${blockUID}`;
React.useEffect(() => {
(async () => {
if(document.getElementById(id) && window.HillChart && !attached) {
let inMotion;
const config = {
target: `#${id}`,
width: 600,
height: 300,
};
const hill = new HillChart([], config);
hill.render();
hill.on("move", () => {
inMotion = true;
});
const dataUID = await getOrCreatePage("HillChart Data");
hill.on("moved", ({id: data, x, y}) => {
const string = `((${data.uid})) ${x.toString()}`;
inMotion = false;
let progress = window.roamAlphaAPI.q(`[
:find ?uid ?string
:in $ ?target_uid ?data_uid
:where
[?target :block/uid ?target_uid]
[?e :block/refs ?target]
[?e :block/string ?string]
[?e :block/uid ?uid]
[?parent :block/children ?e]
[?parent :block/uid ?data_uid]
]`, data.uid, dataUID);
if(progress[0] && progress[0][0]) {
const uid = progress[0][0];
window.roamAlphaAPI.updateBlock({block: {uid, string }})
} else {
window.roamAlphaAPI.createBlock({
location: {"parent-uid": dataUID, order: -1},
block: {string}
});
}
});
setAttached(true);
setInterval(() => {
let childTodos = window.roamAlphaAPI.q(
`[
:find (pull ?child [:block/uid :block/string
{:block/children [:block/uid :block/string]}])
:in $ ?self_uid
:where
[?e :block/uid ?self_uid]
[?e :block/children ?child]
[?child :block/refs ?todo_page]
[?todo_page :node/title "TODO"]
]`,
blockUID
).map(todo => {
let x = window.roamAlphaAPI.q(
`[:find ?uid ?string
:in $ ?target_uid ?data_uid
:where
[?target :block/uid ?target_uid]
[?e :block/refs ?target]
[?e :block/uid ?uid]
[?e :block/string ?string]
[?parent :block/children ?e]
[?parent :block/uid ?data_uid]
]`, todo[0].uid, dataUID
);
let progress = x.length ? Number(x[0][1].slice(14)) : 0;
return {
description: todo[0].string.replace("{{[[TODO]]}}", ""),
color: "blue",
id: todo[0],
x: progress,
};
});
const hash = JSON.stringify(childTodos);
if (!inMotion) hill.replaceAndUpdate(childTodos);
}, 1000);
}
})();
});
const [state, setState] = React.useState(0);
return <svg id={id}/>
}
/* from https://github.com/nagi1/hill-chart/blob/master/src/styles.css */
.chart-hill-main-curve {
fill: none;
opacity: 0.67;
stroke-width: 1.5px;
}
.hill-chart-light .chart-hill-main-curve {
stroke: #6d6d6d;
}
.hill-chart-dark .chart-hill-main-curve {
stroke: #7d7d7d;
}
.hill-chart-circle {
stroke-width: 2;
}
.hill-chart-light .hill-chart-circle {
stroke: #fff;
}
.hill-chart-dark .hill-chart-circle {
stroke: #2b2b2b;
}
.hill-chart-middle-line {
fill: none;
stroke-width: 2.09px;
shape-rendering: crispEdges;
stroke-dasharray: 5, 5;
}
.hill-chart-light .hill-chart-middle-line {
stroke: #cbd5e0;
}
.hill-chart-dark .hill-chart-middle-line {
stroke: #7c7c7c;
}
.hill-chart-bottom-line path {
stroke-width: 1px;
}
.hill-chart-light .hill-chart-bottom-line path {
stroke: #bbb6b6;
}
.hill-chart-dark .hill-chart-bottom-line path {
stroke: #7c7c7c;
}
.hill-chart-text {
font-family: inherit;
text-transform: uppercase;
letter-spacing: 0.05rem;
text-anchor: middle;
shape-rendering: crispEdges;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.hill-chart-light .hill-chart-text {
fill: #646464;
}
.hill-chart-dark .hill-chart-text {
fill: #a5a5a5;
}
.hill-chart-group {
cursor: move;
}
.hill-chart-group > text {
font-family: inherit;
text-anchor: start;
shape-rendering: crispEdges;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
font-size: 1rem;
}
.hill-chart-light .hill-chart-group > text {
fill: #000;
}
.hill-chart-dark .hill-chart-group > text {
fill: #b5b5b5;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment