npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

lindsvg

v1.5.0

Published

Lindenmayer System [Scalable] Vector Graphics

Downloads

47

Readme

lindsvg

lindsvg (pronounced /ˈlɪnds ˈviː ˈdʒiː/), Lindenmayer System [Scalable] Vector Graphics

Simple dependency-free module used to generate SVG images of deterministic L-systems.

Generated SVG tree

Installation

In an npm project

Installing the module is as simple as:

npm install lindsvg

Now you may get it in your scripts as usual: require("lindsvg"), or import * as lindsvg from "lindsvg".

In a browser

lindsvg is available in UMD format which allows you using it either with AMD/CJS compatible module loaders or in global namespace (window.lindsvg). You may get the module sources from such CDNs as jsDelivr or unpkg:

<script src="https://cdn.jsdelivr.net/npm/lindsvg/dist/lindsvg.min.js"></script>

If you rather prefer using ES modules in a browser, just choose the “esm” bundle:

<script type="module">
  import * as lindsvg from "https://cdn.jsdelivr.net/npm/lindsvg/dist/lindsvg.esm.min.js";
  // ...
</script>

Supported commands

The following turtle commands are currently supported by lindsvg:

| Command | Description | | ------------------- | ----------------------------------------------------- | | F | Move forward one step with drawing a line | | B | Move forward one step without drawing a line | | + | Turn left by turning angle (theta) | | - | Turn right by turning angle (theta) | | \| | Reverse direction (turn by 180 degrees) | | ! | Reverse the meaning of + and - | | [ | Push current state of the turtle onto the stack | | ] | Pop a state from the stack and apply it to the turtle | | A,CE,GZ | Auxiliary user-defined rules |

API & examples

The module exports two pairs of methods.

  1. The methods returning ready-to-render L-system’s SVG code as a string:
    • getSVGCode(lsParams[, svgParams]);
    • getMultiPathSVGCode(lsParams[, svgParams]);
  2. The methods returning raw data that you may use to construct the SVG code yourself:
    • getSVGData(lsParams);
    • getMultiPathSVGData(lsParams).

The “multi-path” methods (getMultiPathSVGCode and getMultiPathSVGData) differ from the “normal” methods (getSVGCode and getSVGData) in that they provide the ability for advanced stylisation of branched L-systems. SVG images created using these “multi-path” methods contain several <path> elements, each one for a specific branching level, so they can be stylised differently (color, line width, etc.)

All methods expect L-system parameters object as their first argument. These parameters are explained through the comments in the snippet below. Additionally, the methods getSVGCode and getMultiPathSVGCode may be passed an optional parameter to alter the output SVG settings (refer the comments in the snippet below).

Using “single-path” methods

import {getSVGCode, getSVGData} from "lindsvg";

// L-system parameters
let lsParams = {
  axiom: "A---A",    // The initial codeword (axiom)
  rules: {           // L-system production rules
    F: "F",          // Move forward a step with drawing a line
    B: "B",          // Move forward a step without drawing a line
    A: "B-F+Z+F-BA", // Auxiliary rules...
    Z: "F-FF-F--[--Z]F-FF-F--F-FF-F--",
  },
  alpha: 0,           // Initial angle in radians
  theta: Math.PI / 3, // Angle increment in radians
  step: 15,           // The length of a “turtle” step
  iterations: 7,      // Total number of iterations
};

// Output SVG parameters (all of them are optional)
let svgParams = {
  width: 600,       // Desired SVG element width
  height: 600,      // Desired SVG element height
  padding: 5,       // Additional space to extend the viewBox
  pathAttributes: { // Name to value map for the <path> element attributes
    stroke: "green",
    "stroke-width": "2",
  },
};

// Get ready-to-render L-system’s SVG code as a string...
let svgCode = getSVGCode(lsParams, svgParams);

// ...or get raw data required for manual SVG assemblage
let {pathData, minX, minY, width, height} = getSVGData(lsParams);

An object returned by getSVGData contains path data needed to draw the L-system, as well as the drawing boundaries that are essential for the viewBox attribute.

Using “multi-path” methods

Using “multi-path” methods (getMultiPathSVGCode and getMultiPathSVGData) allows you to specify different path attributes for every <path> element separately, which may make branched L-systems (like plants) look “more naturally”.

For example, to generate the tree demonstrated above (all but foliage) the following options were used:

import {getMultiPathSVGCode, getMultiPathSVGData} from "lindsvg";

// L-system parameters
let lsParams = {
  axiom: "F-FFF-F+F+X",
  rules: {
    F: "F",
    X: "FFF-[-F+F[Y]-[X]]+[+F+F[X]-[X]]",
    Y: "FF-[-F+F]+[+F+FY]",
  },
  alpha: 90 * Math.PI / 180,
  theta: 14 * Math.PI / 180,
  iterations: 6,
  step: 12,
};

// Output SVG parameters
let svgParams = {
  width: 565,
  height: 445,
  padding: 10,
  pathAttributes: {
    stroke: "#514d3a",
    "stroke-width": ["16", "11", "9", "7", "6", "5", "3", "2", "1"],
    "stroke-linecap": ["square", "round" /* the rest items are equal to the last one */],
  },
};

// Get ready-to-render L-system’s SVG code as a string...
let svgCode = getMultiPathSVGCode(lsParams, svgParams);

// ...or get raw data required for manual SVG assemblage
let {multiPathData, minX, minY, width, height} = getMultiPathSVGData(lsParams);

If an attribute array contains fewer elements than the maximum branching depth (e.g. see stroke-linecap in the example above), the missing items are implicitly made equal to the last one. So you don’t need to repeat the same value in the end of the list.

You may also use the special value "n/a" which prevents an attribute from being added on the corresponding <path> element (e.g. when you need to add an attribute only to one or to a few <path>s: {pathAttributes: {transform: ["skewY(-35)", "n/a"]}}).

The property multiPathData in the object returned by getMultiPathSVGData is a list of path data for every <path> element. The list is sorted in the order of increasing branch level (the deeper the branch the higher the index in the array).

Error handling

In case of invalid input L-system parameters, the methods throw a custom exception. You may use it to get a detailed explanation of which parameter(s) failed to pass validation, and format the message as you wish.

import {getSVGCode} from "lindsvg";
import {dump} from "js-yaml";

try {
  console.log(getSVGCode(lsParams, svgParams));
} catch (error) {
  // Log the original message
  console.error(error);
  if (error.name === "LSError") {
    // Get a JSON representation of the error list and format it as YAML
    let errorJSON = error.toJSON();
    console.log(dump(errorJSON, {indent: 4}));
  }
}

Demos

Please, visit the project’s demo web app (installable as a PWA and works offline too). You will find a few built-in L-system collections there, and will also be able to experiment with lindsvg while building your own L-systems.

Also, check out this collection on CodePen to get a few advanced examples of using lindsvg.