@nebula.js/sn-funnel-chart
Version:
A sequential chart visualizing a linear process with connected stages, for example a sales process with potential revenue at each stage.
303 lines (251 loc) • 7.77 kB
Markdown
# @nebula.js/sn-funnel-chart
The funnel chart lets you add a sequential chart showing the connected stages of a process. Each stage decreases and should contain a subset of the previous stage. The decrease is gradual, giving the chart an ever narrower funnel.
## Requirements
Requires `@nebula.js/stardust` version `1.2.0` or later.
## Installing
If you use npm: `npm install @nebula.js/sn-funnel-chart`. You can also load through the script tag directly from [https://unpkg.com](https://unpkg.com/@nebula.js/sn-funnel-chart).
## Usage
The example below shows the number of candidates during sequential stages of a recruitment process. The chart is plotted in `width` mode, where the quantity at each stage is proportional to the upper edge of the segment.
```js
import { embed } from '@nebula.js/stardust';
import funnel from '@nebula.js/sn-funnel-chart';
// 'app' is an enigma app model
const nuked = embed(app, {
types: [{ // register funnel chart
name: 'funnel-chart',
load: () => Promise.resolve(funnel);
}]
});
// Rendering a simple funnel chart
nuked.render({
element: document.querySelector('.funnel'),
type: 'funnel-chart',
fields: ['Hiring Stage', '=Sum(NumberOfCandidates)'],
properties: {
title: 'Recruitment Process',
},
});
```
Funnel chart can represent anything that is decreasing in size,
showing a process that starts at 100% and ends with a lower percentage.
The funnel chart is the opposite to a pyramid graph, which has
increasing stages instead of decreasing stages.
The chart requires one dimension and one measure.
Unlike bar charts, funnel chart segments are centered
to create a funnel shape.
## More examples
### Area mode
You can configure the funnel chart so that the area of each item is
proportional to the measure.
```js
// Rendering a funnel chart in area mode
nuked.render({
element: document.querySelector('.funnel'),
type: 'funnel-chart',
fields: ['Hiring Stage', '=Sum(NumberOfCandidates)'],
properties: {
title: 'Recruitment Process',
funnel: {
mode: 'AREA',
},
},
});
```
### Height mode
The height of each item is proportional to the measure.
```js
// Rendering a funnel chart in height mode
nuked.render({
element: document.querySelector('.funnel'),
type: 'funnel-chart',
fields: ['Hiring Stage', '=Sum(NumberOfCandidates)'],
properties: {
title: 'Recruitment Process',
funnel: {
mode: 'HEIGHT',
},
},
});
```
### Ordering mode
Only order matters, the items have the same height, ordered from top to bottom.
```js
// Rendering a funnel chart in order mode
nuked.render({
element: document.querySelector('.funnel'),
type: 'funnel-chart',
fields: ['Hiring Stage', '=Sum(NumberOfCandidates)'],
properties: {
title: 'Recruitment Process',
funnel: {
mode: 'ORDER',
},
},
});
```
### More configurations
You can also remove the dimension title, show the actual number of
candidates instead of the percentage, or color the stages by measure.
```js
// Rendering a funnel chart with customized look
nuked.render({
element: document.querySelector('.funnel'),
type: 'funnel-chart',
// Defines the fields in `properties`
properties: {
title: 'Recruitment Process',
// Hide dimension title
showDimensionTitle: false,
qHyperCubeDef: {
qDimensions: [
{
qDef: { qFieldDefs: ['Hiring Stage'] },
// Color the dimension by `MedianRequestedSalary`
qAttributeExpressions: [
{
qExpression: 'Avg(MedianRequestedSalary)',
id: 'colorByAlternative',
},
],
},
],
qMeasures: [
{
qDef: { qDef: 'Sum(NumberOfCandidates)' },
},
],
qInterColumnSortOrder: [1, 0],
qInitialDataFetch: [
{
qLeft: 0,
qTop: 0,
qWidth: 2,
qHeight: 5000,
},
],
},
// Show actual number of candidates instead of percentage
dataPoint: {
auto: false,
labelMode: 'value',
},
// Configure color
color: {
auto: false,
byMeasureDef: {
key: 'Avg(MedianRequestedSalary)',
type: 'expression',
},
measureScheme: 'dg',
mode: 'byMeasure',
reverseScheme: true,
},
},
});
```
## Funnel chart plugins
A plugin can be passed into a funnel chart to add or modify its capability
or visual appearance.
A plugin needs to be defined before it can be rendered together with the chart.
```js
// Step 1: define the plugin
// Modifying the look of the dimension title
const dimensionTitlePlugin = {
info: {
name: 'dimension-title-plugin',
type: 'component-definition',
},
fn: ({ keys, layout }) => {
const componentDefinition = {
type: 'text',
// Provide the same name as the exisiting component to override it
key: keys.COMPONENT.DIMENSION_TITLE,
text: 'The percentage of candidates remain after each hiring stage',
layout: {
dock: 'bottom',
},
};
return componentDefinition;
},
};
// Step 2: passing the plugin definition into the render function
// Render a funnel chart with plugins
nuked.render({
element: document.querySelector('#object'),
type: 'sn-funnel-chart',
plugins: [dimensionTitlePlugin],
fields: ['Hiring Stage', '=Sum(NumberOfCandidates)'],
properties: {
title: 'Recruitment Process',
},
});
```
The plugin definition is an object, with two properties `info` and `fn`.
The `fn` returns a `picasso.js` component. To build this component,
some important chart internals are passed into the argument object of `fn`.
```js
// Structure of the argument object of fn
const pluginArgs = {
layout,
keys: {
SCALE: { FILL },
COMPONENT: { FUNNEL, FUNNEL_LABELS, DIMENSION_TITLE },
},
};
```
With plugins, you can either add new components or modify existing components
of the funnel chart.
### Modify existing components
As an example, the positions and the appearance of the funnel labels
can be modified by plugins.
To overide an existing component, `fn` should returns a `picasso.js` component
that has the same `key` as the existing component
(`keys.COMPONENT.FUNNEL_LABELS` in
this example)
```js
// Modifying the look of the funnel labels
const funnelLabelsPlugin = {
info: {
name: 'funnel-labels-plugin',
type: 'component-definition',
},
fn: ({ keys, layout }) => {
const componentDefinition = {
type: 'labels',
// Provide the same name as the exisiting component to override it
key: keys.COMPONENT.FUNNEL_LABELS,
layout: { displayOrder: 2 },
settings: {
sources: [
{
component: keys.COMPONENT.FUNNEL,
selector: '.labelLeft',
strategy: {
type: 'rows',
settings: { align: 0, fill: 'gray', fontSize: '15px' },
},
},
{
component: keys.COMPONENT.FUNNEL,
selector: '.labelCenter',
strategy: {
type: 'rows',
settings: { align: 0.5, fill: 'darkred', fontSize: '15px' },
},
},
],
},
};
return componentDefinition;
},
};
```
### Add new components
The new component can be a standard Picasso component
or a custom Picasso component. The code for adding a new component is
similar to that for modifying an existing component, the only difference
is that the `key` should be different from that of
any of the existing components.
### Plugins disclaimer
- The plugins API is still experimental.
- We can not guarantee our charts to be compatible with all different settings, especially when modifying existing components.