New Research: Supply Chain Attack on Axios Pulls Malicious Dependency from npm.Details →
Socket
Book a DemoSign in
Socket

svg-path-d

Package Overview
Dependencies
Maintainers
1
Versions
11
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

svg-path-d

SVG path data (path[d] attribute content) manipulation library.

latest
Source
npmnpm
Version
0.1.1
Version published
Maintainers
1
Created
Source

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>
`;
// ...

Keywords

svg

FAQs

Package last updated on 25 Jan 2021

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts