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

d3fc-flexi-chart

v0.0.10

Published

A flexible alternative to the d3fc cartesian chart

Downloads

19

Readme

d3fc-flexi-chart

A more flexible alternative to d3fc's Cartesian chart component that renders to canvas or SVG.

Main d3fc package

Installing

npm install d3fc-flexi-chart

API Reference

General API

d3fc provides a component for building a simple Cartesian chart.

d3fc-chart documentation

d3fc-flex-chart takes a similar approach, but builds a chart by composing one or more "layers".

From the d3fc chartCartesian, this:

const cartesian = fc.chartCartesian(d3.scaleLinear(),d3.scaleLinear())
  .yLabel('Sine / Cosine')
  .xLabel('Value')
  .yOrient('left')
  .yDomain(yExtent(data))
  .xDomain(xExtent(data))
  .svgPlotArea(multiSvg);

becomes this:

const chart = fcFlexi.chart()
  .leftLabel('Sine / Cosine')
  .bottomLabel('Value')
  .layers([
    fcFlexi.svgLayer(d3.scaleLinear(), d3.scaleLinear())
      .yOrient('left')
      .yDomain(yExtent(data))
      .xDomain(xExtent(data))
      .plotArea(multiSvg)
  ]);

Most of the properties of the original chartCartesian are now properties of the "layer" component. The chart itself provides properties for leftLabel, topLabel, rightLabel and bottomLabel.

Each layer has its own xScale and yScale, and its own series. This allows you to compose more complex charts with multiple layers, different scales, and multiple x/y axes, while keeping the API simple and familiar.

For example, here's a chart with 3 layers, each sharing the same xScale but having different yScales.

Given the following div:

<div id="sine" style="width: 500px; height: 250px"></div>

The following code renders a chart:

var data = d3.range(50).map((d) => ({
    x: d / 4,
    y: Math.sin(d / 4),
    z: Math.cos(d / 4) * 0.7
}));

// use d3fc-extent to compute the domain for each axis
var xExtent = fc.extentLinear()
  .accessors([d => d.x]);
var yExtent = fc.extentLinear()
  .accessors([d => d.y, d => d.z])
  .pad([0.1, 0.1])

// series (from d3fc-series)
// n.b. the series are rendered using canvas
var line = fc.seriesCanvasLine();
var area = fc.seriesCanvasArea()
  .mainValue(d => d.z);

// combine into a single series
var multi = fc.seriesCanvasMulti()
  .series([area, line]);

var layer = fcFlexi.canvasLayer(d3.scaleLinear(), d3.scaleLinear())
  .yDomain(yExtent(data))
  .xDomain(xExtent(data))
  .plotArea(multi);

// the d3fc-flexi-chart component
var chart = fcFlexi.chart()
  .leftLabel('Sine / Cosine')
  .bottomLabel('Value')
  .layers([layer]);

// render
d3.select('#sine')
  .datum(data)
  .call(chart);

Rendering the following:

The chart is constructed using a single layer that has a pair of scales. The scale configuration properties are rebound (i.e. re-exposed) via the layer component with x and y prefixes. The chart takes care of layout, and will also re-render if the size of the containing element changes.

Styles

The component automatically injects a stylesheet to apply the necessary CSS to the elements. These styles can be augmented with CSS -

d3fc-group.flexi-chart > .bottom-label {
  line-height: 5em;
  color: red;
}

Or through decoration -

chart.decorate(selection => {
  selection.enter()
    .select('.bottom-label')
    .style('line-height', '5em')
    .style('color', 'red')
});

Grid

Internally, the component uses CSS grid layout to arrange the various rendering surfaces and labels. The following diagram shows the grid structure and associated line indicies -

  1             2           3               4            5              6
1 /-------------|-----------|---------------|------------|--------------\
  |             |           |   top gutter  |            |              |
2 |-------------|-----------|---------------|------------|--------------|
  |             |           |    top axis   |            |              |
3 |-------------|-----------|---------------|------------|--------------|
  | left gutter | left axis |   plot area   | right axis | right gutter |
4 |-------------|-----------|---------------|------------|--------------|
  |             |           |  bottom axis  |            |              |
5 |-------------|-----------|---------------|------------|--------------|
  |             |           | bottom gutter |            |              |
6 \-------------|-----------|---------------|------------|--------------/

chart

# fcFlexi.chart()

Constructs a new Flexi chart.

# fcFlexi.bottomLabel(label)
# fcFlexi.topLabel(label)
# fcFlexi.leftLabel(label)
# fcFlexi.rightLabel(label)

If label is specified, sets the text for the given label, and returns the Flexi chart. If label is not specified, returns the label text.

The label value can either be a string, or a function that returns a string. If it is a function, it will be invoked with the data that is 'bound' to the chart. This can be useful if you are rendering multiple charts using a data join.

# chart.layers(layerArray)

If layerArray is specified, sets the array of layer components that this chart should render and returns this chart. If layerArray is not specified, returns the current array of layers.

# chart.mapping(mappingFunc)

If mappingFunc is specified, sets the mapping function to the specified function, and returns this chart. If mappingFunc is not specified, returns the current mapping function.

When rendering the layers, the mapping function is invoked once for each of the layer supplied via the layers property. The purpose of the mapping function is to return the data supplied to each of these layers. The default mapping is the identity function, (d) => d, which results in each layer being supplied with the same data as the chart.

The mapping function is invoked with the data bound to the chart, (data), the index of the current series (index) and the array of layers (layers). A common pattern for the mapping function is to switch on the layer type. For example, a chart could be used to render "price" as well as "volume", with different yScales. In this case, the following would be a suitable mapping function:

const chart = fcFlexi.chart()
    .layers([price, volume])
    .mapping((data, index, layers) => {
      switch(layers[index]) {
        case price:
          return data.price;
        case volume:
          return data.volume;
      }
    });

# chart.decorate(decorateFunc)

If decorateFunc is specified, sets the decorator function to the specified, and returns the Flexi chart. If decorateFunc is not specified, returns the current decorator function.

layer

# fcFlexi.svgLayer(xScale, yScale) # fcFlexi.canvasLayer(xScale, yScale)

Constructs a new SVG/Canvas layer with the given scales.

# fcFlexi.svgLayer({ xScale: xScale, yScale: yScale, xAxis: axisFactory, yAxis: axisFactory }) # fcFlexi.canvasLayer({ xScale: xScale, yScale: yScale, xAxis: axisFactory, yAxis: axisFactory })

Constructs a new SVG/Canvas layer with the given scales and axis components.

If xAxis is specified, it must be an object with the required x-axis factory function (left if yOrient="left" or right if yOrient="right").

If yAxis is specified, it must be an object with the required y-axis factory function (top if xOrient="top" or bottom if xOrient="bottom").

# layer.plotArea(component)

If component is specified, sets the component to render onto the SVG/canvas, and returns the layer. If component is not specified, returns the existing component.

For series that contain a very high number of data-points, rendering to canvas can reduce the rendering time and improve performance. For components that require user-interaction, rendering to SVG can simplify their implementation.

# layer.xAxisHeight(height)

If height is specified, sets the height for the x-axis, and returns the layer. If height is not specified, returns the x-axis height or null if not set. The value should be a string with units (e.g. "2em").

The height value can either be a string, or a function that returns a string. If it is a function, it will be invoked with the data that is 'bound' to the chart. This can be useful if you are rendering multiple charts using a data join.

# layer.yAxisWidth(width)

If width is specified, sets the width for the y-axis, and returns the layer. If width is not specified, returns the y-axis width or null if not set. The value should be a string with units (e.g. "2em").

The width value can either be a string, or a function that returns a string. If it is a function, it will be invoked with the data that is 'bound' to the chart. This can be useful if you are rendering multiple charts using a data join.

# layer.xOrient(orient)
# layer.yOrient(orient)

If orient is specified, sets the orientation for the axis in the given direction, and returns the layer. If orient is not specified, returns the orientation. Valid values for yOrient are left, right or none, and for xOrient they are top, bottom or none.

If an orientation of none is specified for an axis, the axis, and their containers will not be rendered.

The orient value can either be a string, or a function that returns a string. If it is a function, it will be invoked with the data that is 'bound' to the chart. This can be useful if you are rendering multiple charts using a data join.

# layer.xDomain(...)
# layer.yDomain(...)
# layer.xNice(...)
...

The layer exposes the scale properties with either an x or y prefix.

# layer.xTicks(...)
# layer.xTickFormat(...)
# layer.xDecorate(...)
# layer.yTicks(...)
# layer.yTickFormat(...)
# layer.yDecorate(...)
...

The layer exposes the d3fc-axis ticks, tickSize, tickValue, tickFormat, tickArguments, tickSizeInner, tickSizeOuter, tickPadding, tickCenterLabel and decorate properties with either an x or y prefix.