svg-path-d
TypeScript icon, indicating that this package has built-in type declarations

0.1.1 • Public • Published

svg-path-d

SVG path data ('d' attribute) manipulation library.

The d attribute defines a path to be drawn.

A path definition is a list of path commands where each command is composed of a command letter and numbers that represent the command parameters. MDN Web Docs

Installation

npm i svg-path-d

Usage

Step 1: Import the library.

import * as SPD from "svg-path-d";

Step 2: Create a PathNode array.

The PathNode[] is used to represent and manipulate a sequence of path draw commands. It can be created from a string via the fromString(pathData: string): PathNode[] method.

let heart = "M50 30a20 20 0 0140 0q0 30-40 60-40-30-40-60a20 20 0 0140 0z";
let path = SPD.fromString(heart);

It also can be programmatically generated on the fly.

function createHeart(cx: number, cy: number, r: number): SPD.PathNode[] {
  return SPD.makePath([
    { name: "M", x: cx, y: cy - r },
    {
      name: "A",
      rx: r,
      ry: r,
      angle: 0,
      largeArcFlag: false,
      sweepFlag: true,
      x: cx + 2 * r,
      y: cy - r
    },
    {
      name: "Q",
      x1: cx + 2 * r,
      y1: cy + r / 2,
      x: cx,
      y: cy + 2 * r
    },
    {
      name: "Q",
      x1: cx - 2 * r,
      y1: cy + r / 2,
      x: cx - 2 * r,
      y: cy - r
    },
    {
      name: "A",
      rx: r,
      ry: r,
      angle: 0,
      largeArcFlag: false,
      sweepFlag: true,
      x: cx,
      y: cy - r
    },
    { name: "Z" }
  ]);
}

This can also be done with PathBuilder.

function createHeart(
  cx: number,
  cy: number,
  r: number
): SPD.PathNode[] {
  return new SPD.PathBuilder()
    .M(cx, cy - r)
    .a(r, r, 0, 0, 1, 2 * r, 0)
    .q(0, (3 * r) / 2, -2 * r, 3 * r)
    .q(-2 * r, (-3 * r) / 2, -2 * r, -3 * r)
    .a(r, r, 0, 0, 1, 2 * r, 0)
    .z().path;
}

Step 3: Path manipulation.

Path manipulation (or path handling) is the process of changing, transforming, splitting or analyzing paths.

Simple In-Place Transformations.

  • applyTranslate(item: DrawTo, dx: number, dy: number): void;
  • applyVerticalFlip(item: DrawTo): void;
  • applyHorizontalFlip(item: DrawTo): void;

Create Transformed PathNode[].

  • createTransformed(path: PathNode[], matrix: ReadonlyMatrix): PathNode[];
  • createReversed(items: PathNode[]): PathNode[];
// TODO: Add path node manipulation examples here. (splitter/promoter/bounding-rect)

Step 4: Converting PathNode arrays back into strings.

There are two functions which can convert to string individual path draw commands:

  • asString(item: Readonly<DrawTo>, fractionDigits = -1): string;
  • asRelativeString(item: Readonly<PathNode>, fractionDigits = -1): string;

So we can convert a PathNode[] with a desired precision:

const PRECISION = 3;

function pathToString(path: SPD.PathNode[]): string {
  return path.map(item => SPD.asString(item, PRECISION)).join("");
}

function pathToRelativeString(path: SPD.PathNode[]): string {
  return path.map(item => SPD.asRelativeString(item, PRECISION)).join("");
}

function pathToShortestString(path: SPD.PathNode[]): string {
  return path
    .map(item => {
      const s1 = SPD.asString(item, PRECISION);
      const s2 = SPD.asRelativeString(item, PRECISION);
      return s1.length < s2.length ? s1 : s2;
    })
    .join("");
}

Examples

Example #1. A heart with a triangle.

code

const heart = "M10 30a20 20 0 01 40 0 20 20 0 01 40 0q0 30-40 60-40-30-40-60z";

const pathHeart = SPD.fromString(heart);
const pathTriangle = SPD.createReveresed(SPD.makePath(pathHeart.map(toLine)));

const triangle = pathTriangle.map(item => SPD.asString(item)).join("");

const box = SPD.getBoundingRect(pathHeart);

const appDiv: HTMLElement = document.getElementById("app");
appDiv.innerHTML = `
  <h1>Heart</h1>
  <div>
    <svg viewBox="${toViewBox(
      box.left - 1,
      box.top - 1,
      box.right - box.left + 2,
      box.bottom - box.top + 2
    )}">
      <path fill="red" d="${heart + triangle}"/>
    </svg>
  </div>
`;

function toLine(item: SPD.PathNode): SPD.PathNode {
  return SPD.isClosePath(item) || SPD.isMoveTo(item)
    ? { ...item }
    : { name: "L", x: SPD.getX(item), y: SPD.getY(item) };
}

function toViewBox(x: number, y: number, width: number, height: number) {
  return `${x} ${y} ${width} ${height}`;
}

Example #2. From a heart to a triangle.

code

// ...
const pathHeart = SPD.fromString(heart);
const pathTriangle = SPD.makePath(pathHeart.map(toLine));
const morph = SPD.makeInterpolator(pathHeart, pathTriangle);

const src = morph(0).join("");
const dst = morph(1).join("");

const box = SPD.getBoundingRect(pathHeart);

const appDiv: HTMLElement = document.getElementById("app");
appDiv.innerHTML = `
  <h1>Heart Morph</h1>
  <div>
    <svg viewBox="${toViewBox(
      box.left - 1,
      box.top - 1,
      box.right - box.left + 2,
      box.bottom - box.top + 2
    )}">
      <path fill="red" d="${src}">
        <animate id="animate1" begin="1s;animate2.end + 2s" repeatCount="1" fill="freeze" attributeName="d" dur="1s"
          values="${src}; ${dst}" />
        <animate id="animate2" begin="animate1.end + 2s" repeatCount="1" fill="freeze" attributeName="d" dur="1s"
          values="${dst}; ${src}" />
      </path>
    </svg>
  </div>
`;
// ...

Readme

Keywords

Package Sidebar

Install

npm i svg-path-d

Weekly Downloads

2

Version

0.1.1

License

ISC

Unpacked Size

174 kB

Total Files

66

Last publish

Collaborators

  • constf1