New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@thi.ng/hiccup-svg

Package Overview
Dependencies
Maintainers
1
Versions
341
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@thi.ng/hiccup-svg - npm Package Compare versions

Comparing version 5.0.37 to 5.0.38

2

CHANGELOG.md
# Change Log
- **Last updated**: 2023-12-09T19:12:03Z
- **Last updated**: 2023-12-11T10:07:09Z
- **Generator**: [thi.ng/monopub](https://thi.ng/monopub)

@@ -5,0 +5,0 @@

import { fattribs, ff } from "./format.js";
export const circle = (p, r, attribs, ...body) => [
"circle",
fattribs({
...attribs,
cx: ff(p[0]),
cy: ff(p[1]),
r: ff(r),
}),
...body,
const circle = (p, r, attribs, ...body) => [
"circle",
fattribs({
...attribs,
cx: ff(p[0]),
cy: ff(p[1]),
r: ff(r)
}),
...body
];
export {
circle
};

@@ -16,173 +16,185 @@ import { implementsFunction } from "@thi.ng/checks/implements-function";

const ATTRIB_ALIASES = {
alpha: "opacity",
dash: "stroke-dasharray",
dashOffset: "stroke-dashoffset",
lineCap: "stroke-linecap",
lineJoin: "stroke-linejoin",
miterLimit: "stroke-miterlimit",
weight: "stroke-width",
alpha: "opacity",
dash: "stroke-dasharray",
dashOffset: "stroke-dashoffset",
lineCap: "stroke-linecap",
lineJoin: "stroke-linejoin",
miterLimit: "stroke-miterlimit",
weight: "stroke-width"
};
const TEXT_ALIGN = {
left: "start",
right: "end",
center: "middle",
start: "start",
end: "end",
left: "start",
right: "end",
center: "middle",
start: "start",
end: "end"
};
const BASE_LINE = {
top: "text-top",
bottom: "text-bottom",
top: "text-top",
bottom: "text-bottom"
};
const precisionStack = [];
/**
* Takes a normalized hiccup tree of [`thi.ng/geom`](https://thi.ng/geom) and/or
* [thi.ng/hdom-canvas](https://thi.ng/hdom-canvas) shape definitions and
* recursively converts it into an hiccup flavor which is compatible for direct
* SVG serialization. This conversion also involves translation, stringification
* & reorg of various attributes. The function returns new tree. The original
* remains untouched, as will any unrecognized tree/shape nodes.
*
* @remarks
* The `__prec` control attribute can be used (on a per-shape basis) to control
* the formatting used for various floating point values (except color
* conversions). See {@link setPrecision}. Child shapes (of a group) inherit the
* precision setting of their parent.
*
* To control the formatting precision for colors, use [the relevant function in
* the thi.ng/color
* package](https://docs.thi.ng/umbrella/color/functions/setPrecision.html).
*
* @param tree - shape tree
*/
export const convertTree = (tree) => {
if (tree == null)
return null;
if (implementsFunction(tree, "toHiccup")) {
return convertTree(tree.toHiccup());
}
const type = tree[0];
if (isArray(type)) {
return tree.map(convertTree);
}
let attribs = convertAttribs(tree[1]);
if (attribs.__prec) {
precisionStack.push(PRECISION);
setPrecision(attribs.__prec);
}
let result;
switch (tree[0]) {
case "svg":
case "defs":
case "a":
case "g":
result = [type, fattribs(attribs)];
for (let i = 2, n = tree.length; i < n; i++) {
const c = convertTree(tree[i]);
c != null && result.push(c);
}
break;
case "linearGradient":
result = linearGradient(attribs.id, attribs.from, attribs.to, tree[2], {
gradientUnits: attribs.gradientUnits || "userSpaceOnUse",
...(attribs.gradientTransform
? { gradientTransform: attribs.gradientTransform }
: null),
});
break;
case "radialGradient":
result = radialGradient(attribs.id, attribs.from, attribs.to, attribs.r1, attribs.r2, tree[2], {
gradientUnits: attribs.gradientUnits || "userSpaceOnUse",
...(attribs.gradientTransform
? { gradientTransform: attribs.gradientTransform }
: null),
});
break;
case "circle":
result = circle(tree[2], tree[3], attribs, ...tree.slice(4));
break;
case "ellipse":
result = ellipse(tree[2], tree[3][0], tree[3][1], attribs, ...tree.slice(4));
break;
case "rect": {
const r = tree[5] || 0;
result = roundedRect(tree[2], tree[3], tree[4], r, r, attribs, ...tree.slice(6));
break;
const convertTree = (tree) => {
if (tree == null)
return null;
if (implementsFunction(tree, "toHiccup")) {
return convertTree(tree.toHiccup());
}
const type = tree[0];
if (isArray(type)) {
return tree.map(convertTree);
}
let attribs = convertAttribs(tree[1]);
if (attribs.__prec) {
precisionStack.push(PRECISION);
setPrecision(attribs.__prec);
}
let result;
switch (tree[0]) {
case "svg":
case "defs":
case "a":
case "g":
result = [type, fattribs(attribs)];
for (let i = 2, n = tree.length; i < n; i++) {
const c = convertTree(tree[i]);
c != null && result.push(c);
}
break;
case "linearGradient":
result = linearGradient(
attribs.id,
attribs.from,
attribs.to,
tree[2],
{
gradientUnits: attribs.gradientUnits || "userSpaceOnUse",
...attribs.gradientTransform ? { gradientTransform: attribs.gradientTransform } : null
}
case "line":
result = line(tree[2], tree[3], attribs, ...tree.slice(4));
break;
case "hline":
result = hline(tree[2], attribs);
break;
case "vline":
result = vline(tree[2], attribs);
break;
case "polyline":
result = polyline(tree[2], attribs, ...tree.slice(3));
break;
case "polygon":
result = polygon(tree[2], attribs, ...tree.slice(3));
break;
case "path":
result = path(tree[2], attribs, ...tree.slice(3));
break;
case "text":
result = text(tree[2], tree[3], attribs, ...tree.slice(4));
break;
case "img":
result = image(tree[3], tree[2].src, attribs, ...tree.slice(4));
break;
case "points":
result = points(tree[2], attribs.shape, attribs.size, attribs, ...tree.slice(3));
break;
case "packedPoints":
result = packedPoints(tree[2], attribs.shape, attribs.size, attribs, ...tree.slice(3));
break;
default:
result = tree;
);
break;
case "radialGradient":
result = radialGradient(
attribs.id,
attribs.from,
attribs.to,
attribs.r1,
attribs.r2,
tree[2],
{
gradientUnits: attribs.gradientUnits || "userSpaceOnUse",
...attribs.gradientTransform ? { gradientTransform: attribs.gradientTransform } : null
}
);
break;
case "circle":
result = circle(tree[2], tree[3], attribs, ...tree.slice(4));
break;
case "ellipse":
result = ellipse(
tree[2],
tree[3][0],
tree[3][1],
attribs,
...tree.slice(4)
);
break;
case "rect": {
const r = tree[5] || 0;
result = roundedRect(
tree[2],
tree[3],
tree[4],
r,
r,
attribs,
...tree.slice(6)
);
break;
}
if (attribs.__prec) {
setPrecision(precisionStack.pop());
}
return result;
case "line":
result = line(tree[2], tree[3], attribs, ...tree.slice(4));
break;
case "hline":
result = hline(tree[2], attribs);
break;
case "vline":
result = vline(tree[2], attribs);
break;
case "polyline":
result = polyline(tree[2], attribs, ...tree.slice(3));
break;
case "polygon":
result = polygon(tree[2], attribs, ...tree.slice(3));
break;
case "path":
result = path(tree[2], attribs, ...tree.slice(3));
break;
case "text":
result = text(tree[2], tree[3], attribs, ...tree.slice(4));
break;
case "img":
result = image(tree[3], tree[2].src, attribs, ...tree.slice(4));
break;
case "points":
result = points(
tree[2],
attribs.shape,
attribs.size,
attribs,
...tree.slice(3)
);
break;
case "packedPoints":
result = packedPoints(
tree[2],
attribs.shape,
attribs.size,
attribs,
...tree.slice(3)
);
break;
default:
result = tree;
}
if (attribs.__prec) {
setPrecision(precisionStack.pop());
}
return result;
};
const convertAttribs = (attribs) => {
const res = {};
if (!attribs)
return res;
// convertTransforms(res, attribs);
for (let id in attribs) {
const v = attribs[id];
const aid = ATTRIB_ALIASES[id];
if (aid) {
res[aid] = v;
}
else {
convertAttrib(res, id, v);
}
const res = {};
if (!attribs)
return res;
for (let id in attribs) {
const v = attribs[id];
const aid = ATTRIB_ALIASES[id];
if (aid) {
res[aid] = v;
} else {
convertAttrib(res, id, v);
}
return res;
}
return res;
};
const convertAttrib = (res, id, v) => {
switch (id) {
case "font": {
const i = v.indexOf(" ");
res["font-size"] = v.substring(0, i);
res["font-family"] = v.substring(i + 1);
break;
}
case "align":
res["text-anchor"] = TEXT_ALIGN[v];
break;
case "baseline":
res["dominant-baseline"] = BASE_LINE[v] || v;
break;
// case "filter":
// TODO needs to be translated into <filter> def first
// https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/filter
// https://developer.mozilla.org/en-US/docs/Web/SVG/Element/filter
// break;
default:
res[id] = v;
switch (id) {
case "font": {
const i = v.indexOf(" ");
res["font-size"] = v.substring(0, i);
res["font-family"] = v.substring(i + 1);
break;
}
case "align":
res["text-anchor"] = TEXT_ALIGN[v];
break;
case "baseline":
res["dominant-baseline"] = BASE_LINE[v] || v;
break;
default:
res[id] = v;
}
};
export {
convertTree
};

@@ -1,1 +0,4 @@

export const defs = (...defs) => ["defs", {}, ...defs];
const defs = (...defs2) => ["defs", {}, ...defs2];
export {
defs
};
import { fattribs, ff } from "./format.js";
export const ellipse = (p, rx, ry, attribs, ...body) => [
"ellipse",
fattribs({
...attribs,
cx: ff(p[0]),
cy: ff(p[1]),
rx: ff(rx),
ry: ff(ry),
}),
...body,
const ellipse = (p, rx, ry, attribs, ...body) => [
"ellipse",
fattribs({
...attribs,
cx: ff(p[0]),
cy: ff(p[1]),
rx: ff(rx),
ry: ff(ry)
}),
...body
];
export {
ellipse
};
import { isArrayLike } from "@thi.ng/checks/is-arraylike";
import { isString } from "@thi.ng/checks/is-string";
import { css } from "@thi.ng/color/css/css";
export let PRECISION = 3;
/**
* Sets the number of fractional digits used for formatting various floating
* point values in the serialized SVG. The current value can be read via
* {@link PRECISION}.
*
* @param n
*/
export const setPrecision = (n) => (PRECISION = n);
/** @internal */
export const ff = (x) => x === (x | 0) ? String(x) : x.toFixed(PRECISION);
/** @internal */
export const fpoint = (p) => ff(p[0]) + "," + ff(p[1]);
/** @internal */
export const fpoints = (pts, sep = " ") => pts ? pts.map(fpoint).join(sep) : "";
let PRECISION = 3;
const setPrecision = (n) => PRECISION = n;
const ff = (x) => x === (x | 0) ? String(x) : x.toFixed(PRECISION);
const fpoint = (p) => ff(p[0]) + "," + ff(p[1]);
const fpoints = (pts, sep = " ") => pts ? pts.map(fpoint).join(sep) : "";
const DEFAULT_NUMERIC_IDS = [
"font-size",
"opacity",
"stroke-width",
"stroke-miterlimit",
"font-size",
"opacity",
"stroke-width",
"stroke-miterlimit"
];
/**
* Takes an attributes object and a number of attrib IDs whose values should be
* formatted using {@link ff}. Mutates and returns `attribs` object.
*
* @param attribs -
* @param ids -
*
* @internal
*/
const numericAttribs = (attribs, ids) => {
let v;
for (let id of DEFAULT_NUMERIC_IDS.concat(ids)) {
typeof (v = attribs[id]) === "number" && (attribs[id] = ff(v));
}
return attribs;
let v;
for (let id of DEFAULT_NUMERIC_IDS.concat(ids)) {
typeof (v = attribs[id]) === "number" && (attribs[id] = ff(v));
}
return attribs;
};
/**
* Takes an attributes object and converts any `fill`, `stroke` or
* transformation attributes, i.e. `transform`, `rotate`, `scale`, `translate`.
*
* @remarks
* If the element has a `transform` attrib, conversion of the other attribs will
* be skipped, else the values are assumed to be either strings or:
*
* - `transform`: 6-element numeric array (mat23)
* - `translate`: 2-element array
* - `rotate`: number (angle in radians)
* - `scale`: number (uniform scale) or 2-elem array
*
* If no `transform` is given, the resulting transformation order will always be
* TRS. Any string values given will be used as-is and therefore need to be
* complete, e.g. `{ rotate: "rotate(60)" }`
*
* For color related attribs (`fill`, `stroke`), if given value is array-like, a
* number or an
* [`IColor`](https://docs.thi.ng/umbrella/color/interfaces/IColor.html)
* instance, it will be converted into a CSS color string using
* [`css()`](https://docs.thi.ng/umbrella/color/functions/css.html).
*
* String color attribs prefixed with `$` are replaced with `url(#...)` refs
* (used for referencing gradients).
*
* Additional attribute names given (via rest args) will be formatted as numeric
* values (using configured precision, see {@link setPrecision}). Formatting is
* done via {@link numericAttribs}.
*
* Returns updated attribs or `undefined` if `attribs` itself is null-ish.
*
* @param attribs - attributes object
* @param numericIDs - numeric attribute names
*
* @internal
*/
export const fattribs = (attribs, ...numericIDs) => {
if (!attribs)
return;
const res = ftransforms(attribs);
let v;
(v = attribs.fill) && (res.fill = fcolor(v));
(v = attribs.stroke) && (res.stroke = fcolor(v));
return numericAttribs(attribs, numericIDs);
const fattribs = (attribs, ...numericIDs) => {
if (!attribs)
return;
const res = ftransforms(attribs);
let v;
(v = attribs.fill) && (res.fill = fcolor(v));
(v = attribs.stroke) && (res.stroke = fcolor(v));
return numericAttribs(attribs, numericIDs);
};
/**
* Converts any transformation related attribs.
*
* {@link fattribs}
*
* @param attribs - attributes object
*
* @internal
*/
const ftransforms = (attribs) => {
let v;
if ((v = attribs.transform) ||
attribs.translate ||
attribs.scale ||
attribs.rotate) {
if (v) {
attribs.transform = !isString(v)
? `matrix(${[...v].map(ff).join(" ")})`
: v;
delete attribs.translate;
delete attribs.rotate;
delete attribs.scale;
}
else {
attribs.transform = buildTransform(attribs);
}
let v;
if ((v = attribs.transform) || attribs.translate || attribs.scale || attribs.rotate) {
if (v) {
attribs.transform = !isString(v) ? `matrix(${[...v].map(ff).join(" ")})` : v;
delete attribs.translate;
delete attribs.rotate;
delete attribs.scale;
} else {
attribs.transform = buildTransform(attribs);
}
return attribs;
}
return attribs;
};
/**
* @internal
*/
const buildTransform = (attribs) => {
const tx = [];
let v;
if ((v = attribs.translate)) {
tx.push(isString(v) ? v : `translate(${ff(v[0])} ${ff(v[1])})`);
delete attribs.translate;
}
if ((v = attribs.rotate)) {
tx.push(isString(v) ? v : `rotate(${ff((v * 180) / Math.PI)})`);
delete attribs.rotate;
}
if ((v = attribs.scale)) {
tx.push(isString(v)
? v
: isArrayLike(v)
? `scale(${ff(v[0])} ${ff(v[1])})`
: `scale(${ff(v)})`);
delete attribs.scale;
}
return tx.join(" ");
const tx = [];
let v;
if (v = attribs.translate) {
tx.push(isString(v) ? v : `translate(${ff(v[0])} ${ff(v[1])})`);
delete attribs.translate;
}
if (v = attribs.rotate) {
tx.push(isString(v) ? v : `rotate(${ff(v * 180 / Math.PI)})`);
delete attribs.rotate;
}
if (v = attribs.scale) {
tx.push(
isString(v) ? v : isArrayLike(v) ? `scale(${ff(v[0])} ${ff(v[1])})` : `scale(${ff(v)})`
);
delete attribs.scale;
}
return tx.join(" ");
};
/**
* Attempts to convert a single color attrib value. If `col` is prefixed with
* `$`, the value will be converted into a `url(#...)` reference. If not a
* string already, it will be converted into a CSS color string using
* [`css()`](https://docs.thi.ng/umbrella/color/functions/css.html)
*
* {@link fattribs}
*
* @param col - color value
*
* @internal
*/
export const fcolor = (col) => isString(col)
? col[0] === "$"
? `url(#${col.substring(1)})`
: col
: css(col);
/** @internal */
export const withoutKeys = (src, keys) => {
const dest = {};
for (let k in src) {
src.hasOwnProperty(k) && !keys.has(k) && (dest[k] = src[k]);
}
return dest;
const fcolor = (col) => isString(col) ? col[0] === "$" ? `url(#${col.substring(1)})` : col : css(col);
const withoutKeys = (src, keys) => {
const dest = {};
for (let k in src) {
src.hasOwnProperty(k) && !keys.has(k) && (dest[k] = src[k]);
}
return dest;
};
export {
PRECISION,
fattribs,
fcolor,
ff,
fpoint,
fpoints,
setPrecision,
withoutKeys
};
import { fattribs, fcolor, ff } from "./format.js";
const RE_ALPHA_COLOR = /(rgb|hsl)a\(([a-z0-9.-]+),([0-9.%]+),([0-9.%]+),([0-9.]+)\)/;
const gradient = (type, attribs, stops) => [
type,
fattribs(attribs),
...stops.map(gradientStop),
type,
fattribs(attribs),
...stops.map(gradientStop)
];
const gradientStop = ([offset, col]) => {
col = fcolor(col);
// use stop-opacity attrib for safari compatibility
// https://stackoverflow.com/a/26220870/294515
let opacity;
const parts = RE_ALPHA_COLOR.exec(col);
if (parts) {
col = `${parts[1]}(${parts[2]},${parts[3]},${parts[4]})`;
opacity = parts[5];
}
return ["stop", { offset, "stop-color": col, "stop-opacity": opacity }];
col = fcolor(col);
let opacity;
const parts = RE_ALPHA_COLOR.exec(col);
if (parts) {
col = `${parts[1]}(${parts[2]},${parts[3]},${parts[4]})`;
opacity = parts[5];
}
return ["stop", { offset, "stop-color": col, "stop-opacity": opacity }];
};
export const linearGradient = (id, from, to, stops, attribs) => gradient("linearGradient", {
const linearGradient = (id, from, to, stops, attribs) => gradient(
"linearGradient",
{
...attribs,

@@ -26,5 +26,9 @@ id,

x2: ff(to[0]),
y2: ff(to[1]),
}, stops);
export const radialGradient = (id, from, to, fr, r, stops, attribs) => gradient("radialGradient", {
y2: ff(to[1])
},
stops
);
const radialGradient = (id, from, to, fr, r, stops, attribs) => gradient(
"radialGradient",
{
...attribs,

@@ -37,3 +41,9 @@ id,

fr: ff(fr),
r: ff(r),
}, stops);
r: ff(r)
},
stops
);
export {
linearGradient,
radialGradient
};
import { fattribs } from "./format.js";
export const group = (attribs, ...body) => [
"g",
fattribs({ ...attribs }),
...body,
const group = (attribs, ...body) => [
"g",
fattribs({ ...attribs }),
...body
];
export {
group
};
import { fattribs, ff } from "./format.js";
export const image = (pos, url, attribs, ...body) => [
"image",
fattribs({
...attribs,
// TODO replace w/ SVG2 `href` once Safari supports it
"xlink:href": url,
x: ff(pos[0]),
y: ff(pos[1]),
}),
...body,
const image = (pos, url, attribs, ...body) => [
"image",
fattribs({
...attribs,
// TODO replace w/ SVG2 `href` once Safari supports it
"xlink:href": url,
x: ff(pos[0]),
y: ff(pos[1])
}),
...body
];
export {
image
};
import { fattribs, ff } from "./format.js";
export const line = (a, b, attribs, ...body) => [
"line",
fattribs({
...attribs,
x1: ff(a[0]),
y1: ff(a[1]),
x2: ff(b[0]),
y2: ff(b[1]),
}),
...body,
const line = (a, b, attribs, ...body) => [
"line",
fattribs({
...attribs,
x1: ff(a[0]),
y1: ff(a[1]),
x2: ff(b[0]),
y2: ff(b[1])
}),
...body
];
export const hline = (y, attribs) => line([-1e6, y], [1e6, y], attribs);
export const vline = (x, attribs) => line([x, -1e6], [x, 1e6], attribs);
const hline = (y, attribs) => line([-1e6, y], [1e6, y], attribs);
const vline = (x, attribs) => line([x, -1e6], [x, 1e6], attribs);
export {
hline,
line,
vline
};
{
"name": "@thi.ng/hiccup-svg",
"version": "5.0.37",
"version": "5.0.38",
"description": "SVG element functions for @thi.ng/hiccup & related tooling",

@@ -27,3 +27,5 @@ "type": "module",

"scripts": {
"build": "yarn clean && tsc --declaration",
"build": "yarn build:esbuild && yarn build:decl",
"build:decl": "tsc --declaration --emitDeclarationOnly",
"build:esbuild": "esbuild --format=esm --platform=neutral --target=es2022 --tsconfig=tsconfig.json --outdir=. src/**/*.ts",
"clean": "rimraf --glob '*.js' '*.d.ts' '*.map' doc",

@@ -37,8 +39,9 @@ "doc": "typedoc --excludePrivate --excludeInternal --out doc src/index.ts",

"dependencies": {
"@thi.ng/checks": "^3.4.11",
"@thi.ng/color": "^5.6.3",
"@thi.ng/prefixes": "^2.2.7"
"@thi.ng/checks": "^3.4.12",
"@thi.ng/color": "^5.6.4",
"@thi.ng/prefixes": "^2.2.8"
},
"devDependencies": {
"@microsoft/api-extractor": "^7.38.3",
"esbuild": "^0.19.8",
"rimraf": "^5.0.5",

@@ -138,3 +141,3 @@ "tools": "^0.0.1",

},
"gitHead": "25f2ac8ff795a432a930119661b364d4d93b59a0\n"
"gitHead": "5e7bafedfc3d53bc131469a28de31dd8e5b4a3ff\n"
}
import { fattribs, ff, fpoint, fpoints } from "./format.js";
const DEG = 180 / Math.PI;
export const path = (segments, attribs, ...body) => {
let res = [];
for (let seg of segments) {
res.push(seg[0]);
switch (seg[0].toLowerCase()) {
case "a":
res.push([
// rx
ff(seg[1]),
// ry
ff(seg[2]),
// x-axis (theta)
ff(seg[3] * DEG),
// xl
seg[4] ? 1 : 0,
// clockwise
seg[5] ? 1 : 0,
// target xy
ff(seg[6][0]),
ff(seg[6][1]),
].join(","));
break;
case "h":
case "v":
res.push(ff(seg[1]));
break;
case "m":
case "l":
res.push(fpoint(seg[1]));
break;
case "z":
break;
default:
res.push(fpoints(seg.slice(1), ","));
}
const path = (segments, attribs, ...body) => {
let res = [];
for (let seg of segments) {
res.push(seg[0]);
switch (seg[0].toLowerCase()) {
case "a":
res.push(
[
// rx
ff(seg[1]),
// ry
ff(seg[2]),
// x-axis (theta)
ff(seg[3] * DEG),
// xl
seg[4] ? 1 : 0,
// clockwise
seg[5] ? 1 : 0,
// target xy
ff(seg[6][0]),
ff(seg[6][1])
].join(",")
);
break;
case "h":
case "v":
res.push(ff(seg[1]));
break;
case "m":
case "l":
res.push(fpoint(seg[1]));
break;
case "z":
break;
default:
res.push(fpoints(seg.slice(1), ","));
}
return ["path", fattribs({ ...attribs, d: res.join("") }), ...body];
}
return ["path", fattribs({ ...attribs, d: res.join("") }), ...body];
};
export {
path
};
import { fattribs, ff, withoutKeys } from "./format.js";
/**
* Shape instancing group.
*
* @remarks
* The `shape` arg can be an SVG shape `#id` defined elsewhere in the
* document or set to `circle` or `rect` (default).
*
* The `size` arg is only used for the latter two shape types and
* defines the radius or width respectively.
*
* @param pts - points
* @param shape - shape type
* @param size - point size/radius
* @param attribs - attributes
*/
export const points = (pts, shape, size = 1, attribs, ...body) => {
const group = [
"g",
fattribs(withoutKeys(attribs, new Set(["shape", "size"]))),
...body,
];
const href = buildSymbol(group, shape, size);
for (let p of pts) {
// TODO replace w/ SVG2 `href` once Safari supports it
group.push(["use", { "xlink:href": href, x: ff(p[0]), y: ff(p[1]) }]);
}
return group;
const points = (pts, shape, size = 1, attribs, ...body) => {
const group = [
"g",
fattribs(withoutKeys(attribs, /* @__PURE__ */ new Set(["shape", "size"]))),
...body
];
const href = buildSymbol(group, shape, size);
for (let p of pts) {
group.push(["use", { "xlink:href": href, x: ff(p[0]), y: ff(p[1]) }]);
}
return group;
};
/**
* Similar to {@link points}, but takes points from a single large flat
* buffer of coordinates with arbitrary striding.
*
* @remarks
* In addition to `shape` and `size`, the following attribs can be used
* to define the index range and strides:
*
* - `start` - start index (default: 0)
* - `num` - number of points (default: buffer length/2)
* - `cstride` - component stride (default: 1)
* - `estride` - element stride (default: 2)
*
* @param pts - flat point buffer
* @param shape - shape type
* @param size - point size/radius
* @param attribs - other attributes
*/
export const packedPoints = (pts, shape, size = 1, attribs, ...body) => {
attribs = {
start: 0,
cstride: 1,
estride: 2,
...attribs,
};
const { start, cstride, estride } = attribs;
let num = attribs && attribs.num != null
? attribs.num
: ((pts.length - start) / estride) | 0;
const group = [
"g",
fattribs(withoutKeys(attribs, new Set(["start", "cstride", "estride", "shape", "size", "num"]))),
...body,
];
const href = buildSymbol(group, shape, size);
for (let i = start; num-- > 0; i += estride) {
// TODO replace w/ SVG2 `href` once Safari supports it
group.push([
"use",
{ "xlink:href": href, x: ff(pts[i]), y: ff(pts[i + cstride]) },
]);
}
return group;
const packedPoints = (pts, shape, size = 1, attribs, ...body) => {
attribs = {
start: 0,
cstride: 1,
estride: 2,
...attribs
};
const { start, cstride, estride } = attribs;
let num = attribs && attribs.num != null ? attribs.num : (pts.length - start) / estride | 0;
const group = [
"g",
fattribs(
withoutKeys(
attribs,
/* @__PURE__ */ new Set(["start", "cstride", "estride", "shape", "size", "num"])
)
),
...body
];
const href = buildSymbol(group, shape, size);
for (let i = start; num-- > 0; i += estride) {
group.push([
"use",
{ "xlink:href": href, x: ff(pts[i]), y: ff(pts[i + cstride]) }
]);
}
return group;
};
const buildSymbol = (group, shape, size) => {
let href;
if (!shape || shape[0] !== "#") {
href = "_" + ((Math.random() * 1e6) | 0).toString(36);
group.push(["g", { opacity: 0 }, buildShape(shape, href, size)]);
href = "#" + href;
}
else {
href = shape;
}
return href;
let href;
if (!shape || shape[0] !== "#") {
href = "_" + (Math.random() * 1e6 | 0).toString(36);
group.push(["g", { opacity: 0 }, buildShape(shape, href, size)]);
href = "#" + href;
} else {
href = shape;
}
return href;
};
const buildShape = (shape, id, r) => {
const rf = ff(r);
if (shape === "circle") {
return ["circle", { id, cx: 0, cy: 0, r: rf }];
}
const rf2 = ff(-r / 2);
return ["rect", { id, x: rf2, y: rf2, width: rf, height: rf }];
const rf = ff(r);
if (shape === "circle") {
return ["circle", { id, cx: 0, cy: 0, r: rf }];
}
const rf2 = ff(-r / 2);
return ["rect", { id, x: rf2, y: rf2, width: rf, height: rf }];
};
export {
packedPoints,
points
};
import { fattribs, fpoints } from "./format.js";
export const polygon = (pts, attribs, ...body) => [
"polygon",
fattribs({
...attribs,
points: fpoints(pts),
}),
...body,
const polygon = (pts, attribs, ...body) => [
"polygon",
fattribs({
...attribs,
points: fpoints(pts)
}),
...body
];
export {
polygon
};
import { fattribs, fpoints } from "./format.js";
export const polyline = (pts, attribs, ...body) => [
"polyline",
fattribs({
fill: "none",
points: fpoints(pts),
...attribs,
}),
...body,
const polyline = (pts, attribs, ...body) => [
"polyline",
fattribs({
fill: "none",
points: fpoints(pts),
...attribs
}),
...body
];
export {
polyline
};

@@ -168,3 +168,3 @@ <!-- This file is generated - DO NOT EDIT! -->

Package sizes (brotli'd, pre-treeshake): ESM: 2.36 KB
Package sizes (brotli'd, pre-treeshake): ESM: 2.37 KB

@@ -171,0 +171,0 @@ ## Dependencies

import { fattribs, ff } from "./format.js";
export const rect = (p, width, height, attribs, ...body) => roundedRect(p, width, height, 0, 0, attribs, ...body);
export const roundedRect = (p, width, height, rx, ry, attribs, ...body) => {
attribs = fattribs({
...attribs,
x: ff(p[0]),
y: ff(p[1]),
width: ff(width),
height: ff(height),
});
if (rx > 0 || ry > 0) {
attribs.rx = ff(rx);
attribs.ry = ff(ry);
}
return ["rect", attribs, ...body];
const rect = (p, width, height, attribs, ...body) => roundedRect(p, width, height, 0, 0, attribs, ...body);
const roundedRect = (p, width, height, rx, ry, attribs, ...body) => {
attribs = fattribs({
...attribs,
x: ff(p[0]),
y: ff(p[1]),
width: ff(width),
height: ff(height)
});
if (rx > 0 || ry > 0) {
attribs.rx = ff(rx);
attribs.ry = ff(ry);
}
return ["rect", attribs, ...body];
};
export {
rect,
roundedRect
};
import { XML_SVG, XML_XLINK } from "@thi.ng/prefixes/xml";
import { convertTree } from "./convert.js";
import { fattribs } from "./format.js";
/**
* Defines an <svg> root element with default XML namespaces. By default
* currently still defaults to SVG version to 1.1 to support Safari and other
* legacy tooling.
*
* @remarks
* If the `__convert` boolean attrib is enabled, all body elements will be
* automatically converted using {@link convertTree}. The `__convert` attrib
* will be removed afterward and is NOT going to be serialized in the final
* output.
*
* @param attribs - attributes object
* @param body - shape primitives
*/
export const svg = (attribs, ...body) => {
attribs = fattribs({
version: "1.1",
xmlns: XML_SVG,
"xmlns:xlink": XML_XLINK,
...attribs,
}, "width", "height", "stroke-width");
if (attribs.__convert) {
delete attribs.__convert;
body = body.map(convertTree);
}
return ["svg", attribs, ...body];
const svg = (attribs, ...body) => {
attribs = fattribs(
{
version: "1.1",
xmlns: XML_SVG,
"xmlns:xlink": XML_XLINK,
...attribs
},
"width",
"height",
"stroke-width"
);
if (attribs.__convert) {
delete attribs.__convert;
body = body.map(convertTree);
}
return ["svg", attribs, ...body];
};
export {
svg
};
import { fattribs, ff } from "./format.js";
export const text = (p, body, attribs, ...xs) => [
"text",
fattribs({
...attribs,
x: ff(p[0]),
y: ff(p[1]),
}),
body,
...xs,
const text = (p, body, attribs, ...xs) => [
"text",
fattribs({
...attribs,
x: ff(p[0]),
y: ff(p[1])
}),
body,
...xs
];
export {
text
};
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc