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

gradient-path

v2.3.0

Published

A small library to have any gradient follow along any SVG path

Downloads

2,089

Readme

Gradient Path

Travis (.org) npm GitHub

A small library to have any gradient follow along any SVG path

  • 8.8kb gzipped
  • Use on any valid SVG path
  • You can pair it with D3.js, or use it standalone

Gradient Path

This library is inspired of the work of the great Mike Bostock. We opted to remove the depedency on D3 and generalize the code a bit more to allow other people to more easily use it in their projects.

Play around with it in Storybook

Play around with it on CodeSandbox

Read about it on Medium

Installation

Installation instructions depend on whether or not you are using D3.js in your project. If you intend to use D3 alongside gradient-path, then you do not need to install tinygradient. If you're going to use gradient-path standalone within your Javascript project, you must also install those dependencies (but don't worry, both pacakges gzipped together is around 8kb... so it's negligible).

NPM: npm install --save gradient-path Yarn: yarn add gradient-path

Examples

Inspired by the chainable nature of D3, we figured the API should follow suit.

Example in Javascript:

import { GradientPath } from 'gradient-path';

const gp = new GradientPath({
  path: document.querySelector('#gradient-path path'),
  segments: 30,
  samples: 3,
  precision: 2 // Optional
});

gp.render({
  type: 'path',
  fill: [
    { color: '#C6FFDD', pos: 0 },
    { color: '#FBD786', pos: 0.25 },
    { color: '#F7797D', pos: 0.5 },
    { color: '#6DD5ED', pos: 0.75 },
    { color: '#C6FFDD', pos: 1 }
  ],
  width: 10
});

gp.render({
  type: 'circle',
  fill: '#eee',
  width: 3,
  stroke: '#444',
  strokeWidth: 0.5
});

Example in D3.js

import * as d3 from 'd3';
import { getData, strokeToFill } from 'gradient-path';

const segments = 30,
  samples = 3,
  precision = 2, // Optional
  width = 10;

const colors = d3.interpolateRainbow;

// Make sure to remove() the node
const path = d3.select('path').remove();

const data = getData({ path, segments, samples, precision });
const flattenedData = data.flatMap(({ samples }) => samples);

const lineFunc = d3
  .line()
  .x(d => d.x)
  .y(d => d.y);

d3.select('svg')
  .selectAll('path')
  .data(strokeToFill(data, width, precision))
  .enter()
  .append('path')
  .attr('fill', d => colors(d.progress))
  .attr('d', d => lineFunc(d.samples));

d3.select('svg')
  .selectAll('circle')
  .data(flattenedData)
  .enter()
  .append('circle')
  .attr('cx', d => d.x)
  .attr('cy', d => d.y)
  .attr('r', 1.5)
  .attr('fill', '#eee')
  .attr('stroke', '#444')
  .attr('stroke-width', 0.5);

Usage

The only options you can pass into the main functions of Gradient Path (the new GradientPath() class and the getData() function for use with D3) are to always be passed as an object. For instance:

// A new instance of Gradient Path
const gp = new GradientPath({
  path: document.querySelector('#gradient-path path'),
  segments: 30,
  samples: 3,
  precision: 2
});

gp.render(...)

... or with D3:

// Always call remove() after
const path = d3.select('path').remove();

// Our Gradient Path data array
const data = getData({ path, segments, samples, precision });

// D3 code here...

Config Object

The four keys are path, segments, samples, and precision:

  • path (required) - This is the path you intend to convert to a gradient path. It must be a valid DOM node or D3 selection.

  • segments (required) - The number of segments you want in your path or circles. You can also think of this as: "how many different colors do I want to display?"

  • samples (required) - The number of sampled points in each segment. You can think of this as the amount of "detail" in each segment. The more samples, the more specifically the path is rounded.

  • precision (optional) - The amount of decimal places to keep for each point in the path. The default is 2, and for the sake of keeping your path's d attribute short and comprehendible, we recommend this stay the same.

Render function

This only applies to usage with plain Javascript, it doesn't work with D3.

The render() function is the only function available in the GradientPath class. It is responsible for taking it's own configuration object consisting of a few properties:

const colors = [
  { color: '#C6FFDD', pos: 0 },
  { color: '#FBD786', pos: 0.25 },
  { color: '#F7797D', pos: 0.5 },
  { color: '#6DD5ED', pos: 0.75 },
  { color: '#C6FFDD', pos: 1 }
];

gp.render({
  type: 'path',
  fill: colors,
  width: 10,
  stroke: colors,
  strokeWidth: 1
});

You may have as many render() functions as you desire. Here's the structure of the configuration object:

  • type (required) - Must always have a value of path or circle. This designates the type of SVG shape being created.

  • fill (optional) - The fill value of the SVG shape in question. This can be either a string value (#eee or rgb(0, 0, 0)) or a valid tinygradient array.

  • width (optional) - The width of the SVG shape in question. Specifically, this will always refer to the fill.

  • stroke (optional) - The stroke value of the SVG shape in question. This can be either a string value (#eee or rgb(0, 0, 0)) or a valid tinygradient array.

  • strokeWidth (optional) - The stroke width of the SVG shape in question. Specifically, this will always refer to the stroke.

As a general rule, if you use fill then you'll need to define a width. Likewise, if you use a stroke then you will need to defined a strokeWidth. Defaults are not set for these values.

Outlining a stroke

This only applies to usage with D3.

A keen eye might have spotted a subtle difference in how we use getData() when filling an SVG path. In order to work with fill, you'll first need to outline your data. You may do this using the strokeToFill(data, width, precision) function. You can use it like such:

// We got the data in stroke form
const data = getData({ path, segments, samples, precision });

// Time to outline that data!
const outlinedData = strokeToFill(data, width, precision);

// Declare a basic line function
const lineFunc = d3
  .line()
  .x(d => d.x)
  .y(d => d.y);

// Run through our paths
d3.select('svg')
  .selectAll('path')
  .data(outlinedData);
  .enter()
  .append('path')
  .attr('fill', d => colors(d.progress)) // Now we can fill...
  .attr('d', d => lineFunc(d.samples));

A note about antialiasing

As Mike Bostock mentioned in his example:

This example uses a thin stroke in addition to filling the segments. This avoids antialiasing artifacts due to most web browsers not implementing full-scene antialiasing.

This is true and unavoidable. In both his example and in Gradient Path, you may notice small gaps between the edges of each segment. Don't worry, your glasses are working just fine.

This is a well-known issue in every browser I've tested.

The fix is simple but annoying. You can add a very subtle stroke the same color as the fill, like this:

gp.render({
  type: 'path',
  fill: myColors,
  width: 10,
  stroke: myColors,
  strokeWidth: 0.5
});

Antialiasing

Contributing

  1. yarn install - installs all dev dependencies
  2. yarn start - your storybook preview

Fork and PR at will!

Acknowledgements

Mike Bostock, you're my developer crush. It would be an honor to approve a pull request from you.

- @cereallarceny