Skip to content

Commit

Permalink
feat(hiccup-svg): add packedPoints(), update convertTree()
Browse files Browse the repository at this point in the history
  • Loading branch information
postspectacular committed Dec 19, 2019
1 parent 43d0aef commit 67be25e
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 7 deletions.
4 changes: 3 additions & 1 deletion packages/hiccup-svg/src/convert.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { linearGradient, radialGradient } from "./gradients";
import { image } from "./image";
import { hline, line, vline } from "./line";
import { path } from "./path";
import { points } from "./points";
import { packedPoints, points } from "./points";
import { polygon } from "./polygon";
import { polyline } from "./polyline";
import { roundedRect } from "./rect";
Expand Down Expand Up @@ -110,6 +110,8 @@ export const convertTree = (tree: any): any[] => {
return image(tree[3], tree[2].src, attribs);
case "points":
return points(tree[2], attribs.shape, attribs.size, attribs);
case "packedPoints":
return packedPoints(tree[2], attribs.shape, attribs.size, attribs);
default:
return tree;
}
Expand Down
8 changes: 8 additions & 0 deletions packages/hiccup-svg/src/format.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,3 +126,11 @@ export const fcolor = (col: any) =>
? `url(#${col.substr(1)})`
: col
: resolveAsCSS(col);

export const withoutKeys = (src: any, keys: Set<PropertyKey>) => {
const dest: any = {};
for (let k in src) {
src.hasOwnProperty(k) && !keys.has(k) && (dest[k] = src[<any>k]);
}
return dest;
};
86 changes: 80 additions & 6 deletions packages/hiccup-svg/src/points.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import { Vec2Like } from "./api";
import { fattribs, ff } from "./format";
import { fattribs, ff, withoutKeys } from "./format";

/**
* Shape instancing group. The `shape` 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.
* 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
Expand All @@ -18,7 +22,10 @@ export const points = (
size = 1,
attribs?: any
): any[] => {
const group = ["g", fattribs({ ...attribs })];
const group = [
"g",
fattribs(withoutKeys(attribs, new Set(["shape", "size"])))
];
let href: string;
if (!shape || shape[0] !== "#") {
href = "_" + ((Math.random() * 1e6) | 0).toString(36);
Expand All @@ -34,6 +41,73 @@ export const points = (
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: ArrayLike<number>,
shape: string,
size = 1,
attribs?: any
): any[] => {
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"])
)
)
];
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 buildSymbol = (group: any[], shape: string, size: number) => {
let href: string;
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: string, id: string, r: number) => {
const rf = ff(r);
if (shape === "circle") {
Expand Down

0 comments on commit 67be25e

Please sign in to comment.