Rust implementation of NextGraph, a Decentralized and local-first web 3.0 ecosystem
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
nextgraph-rs/ng-app/src/history/gitgraph-js/svg-elements.ts

274 lines
6.0 KiB

export {
createSvg,
createG,
createText,
createCircle,
createRect,
createPath,
createUse,
createClipPath,
createDefs,
createForeignObject,
};
const SVG_NAMESPACE = "http://www.w3.org/2000/svg";
interface SVGOptions {
viewBox?: string;
height?: number;
width?: number;
children?: SVGElement[];
}
function createSvg(options?: SVGOptions): SVGSVGElement {
const svg = document.createElementNS(SVG_NAMESPACE, "svg");
if (!options) return svg;
if (options.children) {
options.children.forEach((child) => svg.appendChild(child));
}
if (options.viewBox) {
svg.setAttribute("viewBox", options.viewBox);
}
if (options.height) {
svg.setAttribute("height", options.height.toString());
}
if (options.width) {
svg.setAttribute("width", options.width.toString());
}
return svg;
}
interface GOptions {
children: Array<SVGElement | null>;
translate?: {
x: number;
y: number;
};
fill?: string;
stroke?: string;
strokeWidth?: number;
onClick?: () => void;
onMouseOver?: () => void;
onMouseOut?: () => void;
}
function createG(options: GOptions): SVGGElement {
const g = document.createElementNS(SVG_NAMESPACE, "g");
options.children.forEach((child) => child && g.appendChild(child));
if (options.translate) {
g.setAttribute(
"transform",
`translate(${options.translate.x}, ${options.translate.y})`,
);
}
if (options.fill) {
g.setAttribute("fill", options.fill);
}
if (options.stroke) {
g.setAttribute("stroke", options.stroke);
}
if (options.strokeWidth) {
g.setAttribute("stroke-width", options.strokeWidth.toString());
}
if (options.onClick) {
g.addEventListener("click", options.onClick);
}
if (options.onMouseOver) {
g.addEventListener("mouseover", options.onMouseOver);
}
if (options.onMouseOut) {
g.addEventListener("mouseout", options.onMouseOut);
}
return g;
}
interface TextOptions {
content: string;
fill?: string;
font?: string;
anchor?: "start" | "middle" | "end";
translate?: {
x: number;
y: number;
};
onClick?: () => void;
}
function createText(options: TextOptions): SVGTextElement {
const text = document.createElementNS(SVG_NAMESPACE, "text");
text.setAttribute("alignment-baseline", "central");
text.setAttribute("dominant-baseline", "central");
text.textContent = options.content;
if (options.fill) {
text.setAttribute("fill", options.fill);
}
if (options.font) {
text.setAttribute("style", `font: ${options.font}`);
}
if (options.anchor) {
text.setAttribute("text-anchor", options.anchor);
}
if (options.translate) {
text.setAttribute("x", options.translate.x.toString());
text.setAttribute("y", options.translate.y.toString());
}
if (options.onClick) {
text.addEventListener("click", options.onClick);
}
return text;
}
interface CircleOptions {
radius: number;
id?: string;
fill?: string;
}
function createCircle(options: CircleOptions): SVGCircleElement {
const circle = document.createElementNS(SVG_NAMESPACE, "circle");
circle.setAttribute("cx", options.radius.toString());
circle.setAttribute("cy", options.radius.toString());
circle.setAttribute("r", options.radius.toString());
if (options.id) {
circle.setAttribute("id", options.id);
}
if (options.fill) {
circle.setAttribute("fill", options.fill);
}
return circle;
}
interface RectOptions {
width: number;
height: number;
borderRadius?: number;
fill?: string;
stroke?: string;
}
function createRect(options: RectOptions): SVGRectElement {
const rect = document.createElementNS(SVG_NAMESPACE, "rect");
rect.setAttribute("width", options.width.toString());
rect.setAttribute("height", options.height.toString());
if (options.borderRadius) {
rect.setAttribute("rx", options.borderRadius.toString());
}
if (options.fill) {
rect.setAttribute("fill", options.fill || "none");
}
if (options.stroke) {
rect.setAttribute("stroke", options.stroke);
}
return rect;
}
interface PathOptions {
d: string;
fill?: string;
stroke?: string;
strokeWidth?: number;
translate?: {
x: number;
y: number;
};
}
function createPath(options: PathOptions): SVGPathElement {
const path = document.createElementNS(SVG_NAMESPACE, "path");
path.setAttribute("d", options.d);
if (options.fill) {
path.setAttribute("fill", options.fill);
}
if (options.stroke) {
path.setAttribute("stroke", options.stroke);
}
if (options.strokeWidth) {
path.setAttribute("stroke-width", options.strokeWidth.toString());
}
if (options.translate) {
path.setAttribute(
"transform",
`translate(${options.translate.x}, ${options.translate.y})`,
);
}
return path;
}
function createUse(href: string): SVGUseElement {
const use = document.createElementNS(SVG_NAMESPACE, "use");
use.setAttribute("href", `#${href}`);
// xlink:href is deprecated in SVG2, but we keep it for retro-compatibility
// => https://developer.mozilla.org/en-US/docs/Web/SVG/Element/use#Browser_compatibility
use.setAttributeNS("http://www.w3.org/1999/xlink", "xlink:href", `#${href}`);
return use;
}
function createClipPath(): SVGClipPathElement {
return document.createElementNS(SVG_NAMESPACE, "clipPath");
}
function createDefs(children: SVGElement[]): SVGDefsElement {
const defs = document.createElementNS(SVG_NAMESPACE, "defs");
children.forEach((child) => defs.appendChild(child));
return defs;
}
interface ForeignObjectOptions {
content: string;
width: number;
translate?: {
x: number;
y: number;
};
}
function createForeignObject(
options: ForeignObjectOptions,
): SVGForeignObjectElement {
const result = document.createElementNS(SVG_NAMESPACE, "foreignObject");
result.setAttribute("width", options.width.toString());
if (options.translate) {
result.setAttribute("x", options.translate.x.toString());
result.setAttribute("y", options.translate.y.toString());
}
const p = document.createElement("p");
p.textContent = options.content;
result.appendChild(p);
return result;
}