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

svg-dom-arrows

v2.3.0

Published

Draw an SVG arrow between two DOM elements

Downloads

1,025

Readme

🏹 SVG DOM Arrows CircleCI

Draw an arrow from one HTML element to another with a simple API and 0 dependencies.

svg-dom-arrows-drag-n-drop-demo

How to get started? ✨

To get started, you'll need 3 things:

  • Your starting DOM element.
  • Your ending DOM element.
  • The style of your SVG path.

Simple implementation:

    const options: PathOptions = {
      start: {
        element: document.getElementById('myGreenBox'),
      },
      end: {
        element: document.getElementById('myGreyBox'),
      },
      style: 'stroke:black;stroke-width:4;fill:transparent',
      appendTo: document.body, // Optional
    };
    const arrow = new LinePath(options);

    // Output

    arrow = {
        containerDiv: HTMLDivElement,// The generated div containing the SVG element
        startBbox: DOMRect, // Internal object used by the class to calculate the arrow path
        endBbox: DOMRect, // Internal object used by the class to calculate the arrow path
        options: PathOptions, // The options object passed
        svgElement: SVGSVGElement, // The generated SVG element containing the path
        svgPathLine: SVGPathElement, // The generated path
    };

ℹ Note: If you don't specify the appendTo option, the SVG path will be rendered but not appended to the document. It will be up to you to append it to a div for example.

Below a screenshot resulting from the code:

line-path-example

Below some demos using vanilla TS/JS and other frameworks/

Demos ✨

You can checkout some demos here with few libs and frameworks so you can get yourself started with the implementation. In a way, svg-dom-arrows will work with anything, it has no dependencies and just uses plain DOM elements. But just in case, I've tried it with Angular, Vue and React as you can see below:

Positioning ➕

Positioning is based on a left and top axis, below a simple visualization of how the axes are based on the element. 0 is at the left of the element, 1 would be at 100% left from the origin.

positioning-axis-guide

You might have noticed that the drawn path starts from position 0,0 of myGreenBox to 0,0 at myGreyBox. If no position is specified, the tool will assume you want it to start from 0,0. You can of course set the position as you like as follows:

    const options: PathOptions = {
      start: {
        element: document.getElementById('myGreenBox'),
        position: {
          top: .5, // 0 being the top of the element
          left: 1, // 0 is at the right of the element
        },
      },
      end: {
        element: document.getElementById('myGreyBox'),
        position: {
          top: .5,
          left: 0,
        },
      },
      style: 'stroke:black;stroke-width:4;fill:transparent',
      appendTo: document.body,
    };
    const arrow = new LinePath(options);

The result would be as follows:

line-path-example-axis

ℹ Note: 0 to 1 are the max values inside the BBox of the DOM element. This does not mean that you're limited to those values. You can experiment with negative values or < 1 values.

Styling 🎨

The style options will be copied directly to the SVG path's style attribute. This being an SVG, it's a little bit different than the usual CSS. Besides what's mostly important is that:

  • stroke:<color> to set the color of the line.
  • stroke-width:<number> to set the thickness of your line.
  • fill:transparent to keep only the line and avoid having a default black color.

You can find a lot of resources about styling your SVG path to suit your needs.

Markers ↗

The API lets you add markers to your SVG path. Markers can be a path or a group, the API just expects an SVGMarkerElement with an ID attribute that it can then append to the defs.

You just need to add the markerId for your start or end element and it will do the job, eg:

/**
 * This function just returns an `SVGMarkerElement` that's already pre-styled and so on
 */
const createMarker  = (): SVGMarkerElement => {
  const arrow = document.createElementNS(SVGNS, 'path');
  const marker = document.createElementNS(SVGNS, 'marker');

  arrow.setAttribute('d', 'M 0 0 L 10 5 L 0 10 z');
  arrow.setAttribute('style', 'fill:white;stroke-width:0.801524;stroke-miterlimit:4;stroke-dasharray:none');

  marker.setAttribute('id', 'marker1'); // <== Make sure to set an id attribute
  /**
   * The below attributes and values are specific to this marker, you'll have to know how markers work
   * to really do something fun. For now you'll have to deal with it manually but I might work on an SVG
   * marker utility.
   */
  marker.setAttribute('refX', '5');
  marker.setAttribute('refY', '5');
  marker.setAttribute('viewBox', '0 0 10 10');
  marker.setAttribute('orient', 'auto-start-reverse'); // <== There is a trick here, be sure to read after the code snippet
  marker.setAttribute('markerWidth', '6');
  marker.setAttribute('markerHeight', '6');
  marker.appendChild(arrow);

  return marker;
};

const s = document.querySelector('.case-1');
const e = document.querySelector('.case-4');
const line = new LinePath({
  start: {
    element: s,
    position: {
      top: .45,
      left: 1,
    },
    markerId: '#marker1', // <== We attribute the marker id for the start of the path
  },
  end: {
    element: e,
    position: {
      top: .5,
      left: 0,
    },
    markerId: '#marker1',  // <== We attribute the same marker to the end of the path
  },
  style: 'stroke:white;stroke-width:4;fill:transparent',
  appendTo: document.body,
  markers: [createMarker()], // Supply your markers as an array to this option
  // Custom CSS classes that you can add for additional styling
  // CSS classes should be as follows: `foo bar baz` and NOT `.foo.bar.baz`
  customClass: {
    container: `container-${idx} foo bar`,
    svgPath: `path-${idx} baz`,
    svgElement: `element-${idx}`,
  }
}, true);

Below the result with an arrow going from the starting to ending DIVs with an arrow marker:

line-path-example-w-markers

As you can see, the marker orients itself correctly, this is due to marker.setAttribute('orient', 'auto-start-reverse') and how the path was drawn it the first place.

To put it simply, you really need to know how markers work to make nice arrows. I'll follow up with a tool that may help solve this issue in the future hopefully! Of course, if you know a guy who knows a guy who knows how to deal with this, please tell them to chime in!

Other options 🐣

You can checkout PathOptions.ts to see what other options you can supply. The most useful for now is manualRender that if you set to true will not render your SVG. You'll have then to call render() to do it.

Adding another Path style 🔌

Adding your own path style is pretty straightforward. The only "drawback" is that you'll have to do it in TypeScript. Anyway, let me walk you through how you can do this (I'll take CurvyPath as an example):

  1. Create your CurvyPath.ts file under src/paths/.
  2. Extend the LinePath class as it's your base class.
  3. Implement your own logic in getPath() and svgPath().
  4. Export your CurvyPath.ts in the barrel file src/paths/index.ts.
  5. Done 🎉.

To get ahold of how this all works, you can checkout LinePath.ts which is your base class. It provides you with everything you need.

And of course you can checkout the /src/paths/ folder to understand how extending the base class makes things easier.

Note ℹ: The only thing you need to respect is to use PathOptions.ts to keep the API consistent. If you need to add options, please add them as optional properties.

💻 How to run the development server ?

Easy, run this command and your server will be on http://localhost/3000:

npm start

🆘 Issues and contributions

If you have an issue with this library or want to contribute, please let me know I'll be happy to interact with you.

⏲ Changelog

  • v2.2.3 : Fixed an issue with the TS types not being built, thanks to @unitythemaker in #47 for his report 👌 .
  • v2.2.2 : Fixed the readme example gif
  • v2.2.1 : Fixed build issue with webpack
  • v2.2.0 : Add example page and expose the options property in Path.ts for ease of use
  • v2.1.6 : Apply security fixes for npm packages
  • v2.1.5 : Deprecated the method recalculate() and renamed it to redraw() suggested by @calumk in #35
  • v2.1.4 : Integrated @JacerOmri PR !34
  • v2.1.3 : Updated .npmignore rules + updated the CI + added github package publish
  • v2.1.2 : Exposed the SVG path, SVG element and div container + general tests fixes
  • v2.1.1 : Fix auto-publish github action
  • v2.1.0 : Added the option to set custom CSS classes for the div container, svg element and svg path as suggested by @rbozan in #32 and #33
  • v2.1.0-beta.1 : Added the option to set custom CSS classes for the div container, svg element and svg path as suggested by @rbozan in #32 and #33
  • v2.0.8 : npm audit fixes + test new github action
  • v2.0.7 : Fixed issue #30 reported by @Flambe related to the besier behavior on small offsets + added github action for auto npm publish 🎉
  • v2.0.7-beta.1 : Fixed issue #30 reported by @Flambe related to the besier behavior on small offsets
  • v2.0.6 : Fixed issue #31 reported by @Flambe.
  • v2.0.6-beta.1 : Fixed issue #31 reported by @Flambe.
  • v2.0.5: e2e tests + fixed issue #29 with typings not being bundled after the build thanks to @Flambe.
  • v2.0.4: Fixed issue #27 related to positioning relatively to the appendTo element + fixed unit tests thanks to @jan-dolejsi.
  • v2.0.4-beta.1: Fixed issue #27 related to positioning relatively to the appendTo element.
  • v2.0.2: Documented the code, added SvgProportions type, recalculate() method, and improved readme.
  • v2.0.1: Fixed issue with typings not being packaged.
  • v2.0.0a: Rewrote from the ground up the full API and implementation.
  • v1.0.0: Forked and improved from sasza2/arrows