Skip to content

Commit

Permalink
Updating readme with examples and warning, also aadding an additional…
Browse files Browse the repository at this point in the history
… check
  • Loading branch information
lovettbarron committed Jul 8, 2024
1 parent beb77f2 commit 2badcca
Show file tree
Hide file tree
Showing 6 changed files with 143 additions and 129 deletions.
Binary file added example/currentrender.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added example/test-for-plugin.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@
"gen:docs": "rm -rf ./docs/api && typedoc --options typedoc.cjs",
"prepublishOnly": "npm run build",
"prepare": "lefthook install",
"release": "npm run prepublishOnly && npm changeset publish",
"release": "npm run prepublishOnly && changeset publish",
"devpub": "yalc push --scripts --update --replace"
},
"devDependencies": {
Expand Down
12 changes: 11 additions & 1 deletion readme.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
# rehype-jsoncanvas

NOTE: This project is currently in development/prove of concept stage and isn't usable in a project. But feel free to fork, PR, or add issues if you have requests.
NOTE: This project is currently in active development/prove of concept stage and isn't usable in a project. But feel free to fork, PR, or add issues if you have requests and I will respond quickly.

Its up on NPM but might not work in your environment/context. Let me know if so

Finally, I know it doesn't work on react-markdown atm because it doesn't support async plugins. I'm going to try and fix this, but suggest using the unified ecosystem directly.

## What does this do?

A rehype plugin that renders a [json-canvas](https://jsoncanvas.org/) element, probably downstream from a markdown file.

Rendered Canvas inside of Obsidian
![](./example/test-for-plugin.png)

Rendered canvas as svg on [next shims](https://github.com/lovettbarron/shims)
![](./example/currentrender.png)

## Why does it do it?

Because I really like the obsidian json-canvas format, and would like to leverage it a bit more simply in my websites.
Expand Down
174 changes: 87 additions & 87 deletions src/jsoncanvas.ts
Original file line number Diff line number Diff line change
@@ -1,80 +1,80 @@
import type { Element } from "hast"
import { s } from "hastscript"
import type { Element } from "hast";
import { s } from "hastscript";

import type { Edge, GenericNode, JSONCanvas } from "@trbn/jsoncanvas"
import type { Edge, GenericNode, JSONCanvas } from "@trbn/jsoncanvas";

import { type Options, applyDefaults } from "./options"
import { type Options, applyDefaults } from "./options";

import { drawEmbedded, drawMarkdownEmbed } from "./embed"
import { drawEmbedded, drawMarkdownEmbed } from "./embed";

function calculateMinimumCanvasSize(jsc: JSONCanvas) {
let minX = Number.POSITIVE_INFINITY
let minY = Number.POSITIVE_INFINITY
let maxX = Number.NEGATIVE_INFINITY
let maxY = Number.NEGATIVE_INFINITY
let minX = Number.POSITIVE_INFINITY;
let minY = Number.POSITIVE_INFINITY;
let maxX = Number.NEGATIVE_INFINITY;
let maxY = Number.NEGATIVE_INFINITY;

for (const node of jsc.getNodes()) {
minX = Math.min(minX, node.x)
minY = Math.min(minY, node.y)
maxX = Math.max(maxX, node.x + node.width)
maxY = Math.max(maxY, node.y + node.height)
minX = Math.min(minX, node.x);
minY = Math.min(minY, node.y);
maxX = Math.max(maxX, node.x + node.width);
maxY = Math.max(maxY, node.y + node.height);
}

const canvasWidth = maxX - minX
const canvasHeight = maxY - minY
const canvasWidth = maxX - minX;
const canvasHeight = maxY - minY;

return { canvasWidth, canvasHeight, offsetX: -minX, offsetY: -minY }
return { canvasWidth, canvasHeight, offsetX: -minX, offsetY: -minY };
}

export function validate(jsonCanvasData: JSONCanvas) {
// Use the typescript lib to vlaidate?
console.log("Validate!", jsonCanvasData)
return true
console.log("Validate!", jsonCanvasData);
return true;
}

export function render(
jsc: JSONCanvas,
config?: Partial<Options>,
config?: Partial<Options>
): Element | null {
const options = applyDefaults(config)
const options = applyDefaults(config);

const { canvasWidth, canvasHeight, offsetX, offsetY } =
calculateMinimumCanvasSize(jsc)
calculateMinimumCanvasSize(jsc);

// Init Canvas objects
const svg = initRender(canvasWidth + offsetX, canvasHeight + offsetY)
const svg = initRender(canvasWidth + offsetX, canvasHeight + offsetY);

if (svg === null) return null
if (svg === null) return null;

// Draw nodes
for (const node of jsc.getNodes()) {
drawNode(svg, node, options)
drawNode(svg, node, options);
}

// Draw Edges
for (const edge of jsc.getEdges()) {
const fromNode = jsc.getNodes().find((node) => node.id === edge.fromNode)
const toNode = jsc.getNodes().find((node) => node.id === edge.toNode)
const fromNode = jsc.getNodes().find((node) => node.id === edge.fromNode);
const toNode = jsc.getNodes().find((node) => node.id === edge.toNode);
if (toNode !== undefined && fromNode !== undefined)
drawEdge(svg, toNode, fromNode, edge, options)
drawEdge(svg, toNode, fromNode, edge, options);
}

return renderToBuffer(svg)
return renderToBuffer(svg);
}

function renderToBuffer(svg: Element, config?: Partial<Options>): Element {
const options = applyDefaults(config)
console.log("Rendering", svg, options)
return svg
const options = applyDefaults(config);
console.log("Rendering", svg, options);
return svg;
}

function initRender(
width: number,
height: number,
config?: Partial<Options>,
config?: Partial<Options>
): Element {
const options = applyDefaults(config)
console.log(options)
const options = applyDefaults(config);
console.log(options);
const BASE_SVG_PROPS = {
version: "1.1",
xmlns: "http://www.w3.org/2000/svg",
Expand All @@ -85,7 +85,7 @@ function initRender(
"fill-rule": "evenodd",
fill: "currentColor",
stroke: "currentColor",
}
};

const props = {
...BASE_SVG_PROPS,
Expand All @@ -95,44 +95,44 @@ function initRender(
renHeight: height as number,
viewBox: `0 0 ${width} ${height}`,
preserveAspectRatio: "none",
}
};

const svg = s("svg", props)
svg.properties
return svg
const svg = s("svg", props);
svg.properties;
return svg;
}

async function drawNode(
svg: Element,
node: GenericNode | any,
config?: Partial<Options>,
config?: Partial<Options>
) {
const options = applyDefaults(config)
const options = applyDefaults(config);

let fillStyle = "rgba(255, 255, 255, .5)"
let strokeStyle = "rgba(0,0,0,1)"
let fillStyle = "rgba(255, 255, 255, .5)";
let strokeStyle = "rgba(0,0,0,1)";

if (node.color === "1") {
fillStyle = "rgba(255, 0, 0, .5)"
strokeStyle = "rgba(255,0,0,1)"
fillStyle = "rgba(255, 0, 0, .5)";
strokeStyle = "rgba(255,0,0,1)";
} else if (node.color === "2") {
fillStyle = "rgba(255, 100, 0, .5)"
strokeStyle = "rgba(255,100,0,1)"
fillStyle = "rgba(255, 100, 0, .5)";
strokeStyle = "rgba(255,100,0,1)";
} else if (node.color === "3") {
fillStyle = "rgba(255, 255, 0, .5)"
strokeStyle = "rgba(255,255,0,1)"
fillStyle = "rgba(255, 255, 0, .5)";
strokeStyle = "rgba(255,255,0,1)";
} else if (node.color === "4") {
fillStyle = "rgba(0, 255, 100, .5)"
strokeStyle = "rgba(0,100,0,1)"
fillStyle = "rgba(0, 255, 100, .5)";
strokeStyle = "rgba(0,100,0,1)";
} else if (node.color === "5") {
fillStyle = "rgba(0, 255, 255, .5)"
strokeStyle = "rgba(0,255,255,1)"
fillStyle = "rgba(0, 255, 255, .5)";
strokeStyle = "rgba(0,255,255,1)";
} else if (node.color === "6") {
fillStyle = "rgba(100, 10, 100, .5)"
strokeStyle = "rgba(100,10,100,1)"
fillStyle = "rgba(100, 10, 100, .5)";
strokeStyle = "rgba(100,10,100,1)";
}

const group = s("g")
const group = s("g");

const rect = s("rect", {
x: node.x + <number>svg.properties.renWidth / 2,
Expand All @@ -144,12 +144,12 @@ async function drawNode(
stroke: strokeStyle,
fill: fillStyle,
"stroke-width": options.lineStrokeWidth,
})
});

group.children.push(rect)
group.children.push(rect);

drawEmbedded(svg, group, node)
drawMarkdownEmbed(svg, group, node)
drawEmbedded(svg, group, node);
drawMarkdownEmbed(svg, group, node);

// Group Label
if (node.label) {
Expand All @@ -162,9 +162,9 @@ async function drawNode(
"font-size": 20,
"stroke-width": 1,
},
node.label,
)
group.children.push(t)
node.label
);
group.children.push(t);
}

// Node within a rect
Expand All @@ -182,78 +182,78 @@ async function drawNode(
"font-size": 20,
"stroke-width": 1,
},
node.text,
)
group.children.push(t)
node.text
);
group.children.push(t);
}

svg.children.push(group)
svg.children.push(group);
}

function drawEdge(
svg: Element,
toNode: GenericNode,
fromNode: GenericNode,
edge: Edge | any,
config?: Partial<Options>,
config?: Partial<Options>
) {
const options = applyDefaults(config)
if (svg === null || svg === undefined) return
const options = applyDefaults(config);
if (svg === null || svg === undefined) return;

const cWidth = <number>svg.properties.renWidth || (1 as number)
const cHeight = <number>svg.properties.renHeight || (1 as number)
const cWidth = <number>svg.properties.renWidth || (1 as number);
const cHeight = <number>svg.properties.renHeight || (1 as number);

if (fromNode && toNode) {
let startX =
fromNode.x +
(edge.fromSide === "top" || edge.fromSide === "bottom"
? fromNode.width / 2
: fromNode.width) +
cWidth / 2
let startY = fromNode.y + fromNode.height / 2 + cHeight / 2
cWidth / 2;
let startY = fromNode.y + fromNode.height / 2 + cHeight / 2;
let endX =
toNode.x +
(edge.toSide === "top" || edge.toSide === "bottom"
? toNode.width / 2
: toNode.width) +
cWidth / 2
let endY = toNode.y + toNode.height / 2 + cHeight / 2
cWidth / 2;
let endY = toNode.y + toNode.height / 2 + cHeight / 2;

if (edge.fromSide === "left") {
startX = fromNode.x + cWidth / 2
startX = fromNode.x + cWidth / 2;
} else if (edge.fromSide === "top") {
startY = fromNode.y + cHeight / 2
startY = fromNode.y + cHeight / 2;
} else if (edge.fromSide === "bottom") {
startY = fromNode.y + fromNode.height + cHeight / 2
startY = fromNode.y + fromNode.height + cHeight / 2;
}

if (edge.toSide === "right") {
endX = toNode.x + toNode.width + cWidth / 2
endX = toNode.x + toNode.width + cWidth / 2;
} else if (edge.toSide === "top") {
endY = toNode.y + cHeight / 2
endY = toNode.y + cHeight / 2;
} else if (edge.toSide === "bottom") {
endY = toNode.y + toNode.height + cHeight / 2
endY = toNode.y + toNode.height + cHeight / 2;
} else if (edge.toSide === "left") {
endX = toNode.x + cWidth / 2
endX = toNode.x + cWidth / 2;
}

// Change the control point logic based on fromSide/toSide
const cp1 = {
x: startX,
y: endY,
}
};

const cp2 = {
x: endX,
y: startY,
}
};

const line = s("path", {
d: `M ${startX} ${startY} C ${cp1.x} ${cp1.y}, ${cp2.x} ${cp2.y}, ${endX} ${endY}`,
stroke: "black",
"stroke-width": options.lineStrokeWidth,
fill: "none",
})
svg.children.push(line)
});
svg.children.push(line);
}
}
Loading

0 comments on commit 2badcca

Please sign in to comment.