Published
Edited
May 3, 2020
1 fork
Insert cell
md`# Remnote Collapsible Trees`
Insert cell
md`## Remnote get-by-ID API`
Insert cell
APIKEY = '23fb45232bcc0a718875ef6c0e326035' // TODO(ddohan): Deprecate this bot API key on test account
Insert cell

USERID = '8WfF3x3dP7ezp5cAJ'
Insert cell
ROOTID = 'nh8j6pZ5RDFDhfgQZ'
Insert cell
fetch_rem = (id, callback = (response) => { return response } ) => fetch("https://www.remnote.io/api/v0/get", {
body: JSON.stringify({
"apiKey": APIKEY,
"userId": USERID,
"remId": id,
}),
method: "POST",
}).then(response => {
return response.json();
}).then(callback);
Insert cell
fetch_rem(ROOTID,) // (response) => { return console.log(response) } )
Insert cell
sleep = (milliseconds) => {
return new Promise(resolve => setTimeout(resolve, milliseconds))
}

Insert cell
list = [1, 2, 3, 4]
Insert cell
doSomething = async () => {
for (const item of list) {
await sleep(2000)
console.log('🦄')
}
}
Insert cell
doSomething()
Insert cell
md`# Rem crawler`
Insert cell
Insert cell
md`# Process to Graph`
Insert cell
rems_to_graph = (rems, spacing = 100, jitter = 50, width = 5) => {
const graph = {edges: [], nodes: []}
let idx = 0
let y = 0
let x = 0
for (const rem of Object.values(rems)) {
x = x + spacing
if (idx % width == 0) {
y += spacing
x = 0
}
idx = idx + 1
const node = {
id: rem._id,
x: x + (Math.random() - 0.5) * jitter,
y: y + (Math.random() - 0.5) * jitter,
width: 80,
height: 80,
label: rem.name[0],
}
graph['nodes'].push(node)
for (const child_id of rem.children) {
const edgename = `${rem._id}_${child_id}`
const edge = {
id: edgename,
source: rem._id,
target: child_id,
//label: edgename,
}
graph['edges'].push(edge)
}
}
return graph
}
Insert cell
remdb = await crawl_rem(ROOTID, 100) // Crawl
Insert cell
remdb
Insert cell
resolve_name = (rems, uid) => {
let name = rems[uid].name[0];
if (name == undefined || name.length == undefined) {
console.log(name)
name = '<error>';
}
return name
}
Insert cell
make_tree = (rems, root) => {
const process_rem = (rem) => {
const out = {id: rem._id,
totalFinishIncomeAmtString: "", //22.47 Billion",
finishRate: Math.random() * 0.1 + 0.9,
status: "S"}
out.name = resolve_name(rems, rem._id)
const children = []
for (const child_id of rem.children) {
const child = rems[child_id]
const child_node = process_rem(child)
children.push(child_node)
}
out.children = children
return out
}
return process_rem(rems[root])
}
Insert cell
tree = make_tree(remdb, ROOTID)
Insert cell
md `# Render Graph`
Insert cell
TreeDemo = {
// for Observable Cell
const wrapper = html`<div style="text-align: center;"></div>`;
const container = html`<div></div>`
wrapper.appendChild(container);
yield wrapper;
// Demo Code
// the tree graph data
const data = tree;

// custom a node type
G6.registerNode(
'flow-rect',
{
draw(cfg, group) {
const {
name = '',
status,
totalFinishIncomeAmtString,
finishRate,
collapsed,
} = cfg;
const rectConfig = {
width: 200,
height: 74,
lineWidth: 1,
fontSize: 12,
fill: '#fff',
radius: 4,
stroke: status === 'I' ? '#DCDFE5' : '#1890FF',
opacity: 1,
};
if (finishRate < 0.95) rectConfig.stroke = '#EB2F96';

const textConfig = {
textAlign: 'left',
textBaseline: 'top',
};

const rect = group.addShape('rect', {
attrs: {
x: 0,
y: 0,
...rectConfig,
},
});

// label title
group.addShape('text', {
attrs: {
...textConfig,
x: 12,
y: 8,
text: name,
fontSize: 20,
fill: '#000',
cursor: 'pointer',
},
});

// label count
group.addShape('text', {
attrs: {
...textConfig,
x: 12,
y: 34,
text: totalFinishIncomeAmtString,
fontSize: 20,
fill: '#000',
},
});

// label percentage
group.addShape('text', {
attrs: {
...textConfig,
x: 188,
y: 37,
text: `${((finishRate || 0) * 100).toFixed(2)}%`,
fontSize: 14,
textAlign: 'right',
fill: rectConfig.stroke,
},
});

// bottom line
group.addShape('rect', {
attrs: {
x: 0,
y: 70,
width: rectConfig.width,
height: 4,
radius: [0, 0, rectConfig.radius, rectConfig.radius],
fill: '#DCDFE5',
},
});

// bottom percent
group.addShape('rect', {
attrs: {
x: 0,
y: 70,
width: rectConfig.width * cfg.finishRate,
height: 4,
radius: [0, 0, 0, rectConfig.radius],
fill: rectConfig.stroke,
},
});

if (cfg.children && cfg.children.length) {
// collapse circle
group.addShape('circle', {
attrs: {
x: rectConfig.width,
y: rectConfig.height / 2,
r: 8,
stroke: rectConfig.stroke,
fill: '#fff',
},
name: 'collapse-marker'
});

// collpase text
group.addShape('text', {
attrs: {
x: rectConfig.width,
y: rectConfig.height / 2,
width: 16,
height: 16,
textAlign: 'center',
textBaseline: 'middle',
text: collapsed ? '+' : '-',
fontSize: 16,
fill: rectConfig.stroke,
cursor: 'pointer',
},
name: 'collapse-marker-text'
});
}
return rect;
}
},
'rect',
);

// Instantiate the Graph
const graph = new G6.TreeGraph({
container, // the html container for the graph
// the size of the graph
width: 1000,
height: 1000,
fitView: true, // fit the graph to the view
modes: { // intraction modes
default: [ 'drag-canvas', {
type: 'collapse-expand',
shouldBegin: e => {
if (e.target.get('name') === 'collapse-marker' || e.target.get('name') === 'collapse-marker-text') {
graph.setItemState(e.item, 'collapse', e.item.getModel().collapsed ? 'yes' : 'no');
return true;
}
return false;
}
}]
},
defaultNode: { // global node configuration
type: 'flow-rect'
},
defaultEdge: { // global edge configuration
type: 'cubic-horizontal'
},
nodeStateStyles: { // node styles in different states
'collapse:yes': {
'collapse-marker-text': {
text: '-',
},
},
'collapse:no': {
'collapse-marker-text': {
text: '+',
},
}
},
layout: { // layout algorithm for the tree graph
type: 'compactBox',
direction: 'LR',
getVGap: function getVGap() {
return 50;
},
getHGap: function getHGap() {
return 100;
},
}
});
// Load the data
graph.data(data);
// Render the graph
graph.render();
}
Insert cell
md`#CSS Style`
Insert cell
Insert cell
import { collapsedCSS } from "@j-f1/css-template-tag"
Insert cell
md`# Lib`
Insert cell
G6 = require("@antv/g6@3.4.1");
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