@flourish/legend
v8.0.3
Published
Flourish module for making legend
Downloads
196
Maintainers
Keywords
Readme
Flourish legend component
Introduction
The legend component adds legends to a Flourish template. There are currently three types:
- discrete (color) (displays as a series of swatches)
- continuous (color) (displays as a color band)
- continuous (size) (displays as a small and large circle)
Multiple instances of a legend may be added to a template.
The legends are added to a main legend container. The legend container controls generic styling such as font size, aligment and orientation.
Installation and initialization
Install using
npm install --save @flourish/legend
Then initialize the legends like this in the template (make sure this is executed before draw()
is called):
import { createLegendContainer, createDiscreteColorLegend, createContinuousColorLegend, createContinuousSizeLegend } from "@flourish/legend";
const legend_container = createLegendContainer(state.legend_container);
const legend_categorical = createDiscreteColorLegend(state.legend_categorical);
const legend_continuous = createContinuousColorLegend(state.legend_continuous);
const legend_size = createContinuousSizeLegend(state.legend_size);
legend_container
.appendTo(layout.getSection("legend"))
.add([
legend_categorical,
legend_continuous,
legend_size
]);
Then update the legends like this:
legend_categorical
.data(...)
...
legend_continuous
.data(...)
...
legend_size
.data(...)
...
legend_container.update()
If you use the legend container there's no need to call .update
on each legend.
Add legend settings to template
In your template.yml, first add settings for the legend container:
- property: legend_container
import: "@flourish/legend/container"
And add the legend container settings to the state:
state: {
"legend_container": {}
}
Add settings for specific legends
- property: legend_categorical
import: "@flourish/legend/discrete-color"
state: {
"legend_categorical": {}
}
- property: legend_continuous
import: "@flourish/legend/continuous-color"
state: {
"legend_continuous": {}
}
- property: legend_size
import: "@flourish/legend/continuous-size"
state: {
"legend_size": {}
}
Legend container
Setting up the legend container
The legend container is used to set generic styles (including settings) that apply to all the legend instances inside the container, such as font size, alignment. The legend container has 3 methods:
.add([legend_instances])
- takes an (array of) legend instances that will be appended to the legend container.appendTo(target_element)
- takes a target node element and will append the container to target element.update()
- updates the legend container and all the containing legends
Using the legend without a legend container
The legend container is completely optional. So if you are working in a template and want to control the container and generic sizes in a different way, you can skip the legend container, and use the appendTo()
and update()
function of each individual legend instance.
Discrete / Categorical (color) legend
Add legend items to the legend and customise it
legend_categorical
.data(array, color_function(optional)) // See explanation below
.filtered(["Brazil"]) // Array, items that should have low opacity
.on("click", function(d) { // Add event listener to legend items (eg. "click", "mouseover", etc.)
console.log(this, d, i); // (Legend item node element, {label: "Brazil", color: "#333333", index: "0"}, index)
});
Adding data to the legend
You need to pass the data method an array of strings as its first argument. This will be a list of all the labels for the legend items. The second argument is the color scale.
const getColor = initializeColors(state.color).getColor // Using Flourish custom colors module
// const getColor = function(label, i) { return color_list[label]; } // Or create your own function, referencing an object/array with colors
const legend_items = ["Brazil", "Argentina"]
legend_categorical.data(legend_items, getColor)
Alternative way of giving data to the categorical legend.
Alternatively you can do it in a more manual way where you create an array of objects that has a label and a color property. The label will be the label displayed for that legend item, and the color will be the color of the swatch.
const legend_items = [
{
label: "Brazil",
color: "#ff0000"
},
{
label: "Argentina",
color: "#000000"
}
]
legend_categorical.data(legend_items);
Using icons in categorical legends
By default, categorical legends use basic swatches whose size and roundness can be customised by the user via swatch settings.
However, you can use a discrete/categorical legend instance as an icon legend. This could be as a separate legend just for icons, or as a key to both icons and categorical colors at once.
To swap out basic swatches for icons, the data passed to a categorical legend should use the array of objects method explained above, but each object should include an icon property.
The legend supports three types of icon, so each legend item's data for icon
must
include one of the following properties:
- For SVG icons,
path_string
which is an SVG path - For image icons,
url
which is a valid image URL - For HTML icons (such as a snippet which generates a Font Awesome icon),
html
which is valid HTML code
For image icons, the color
property in the legend data will be ignored, as image icons
cannot be filled in the same way SVG icons can. For HTML icons, if color
exists, the legend adds styling to color the added HTML by this color.
Icon data can also optionally include height
and width
. If omitted, icons will
use the icon_height
setting value and set width to auto
.
For SVG icons only, add outline
and/or stroke_thickness
properties at the top-level
of legend data to create icons that are outlines only rather than filled. outline
is
a Boolean value, while stroke_thickness
is a number specified as a proportion of the
icon height.
For example, an icon legend's data might look like:
const legend_items = [
// An SVG icon
{
label: "Buses",
color: "#4328e7",
icon: {
path_string: "M488 128h-8V80c0-44.8-99.2-80-224-80S32 35.2 32...",
height: 512,
width: 576
},
outline: true,
stroke_thickness: 0.05
}
// An HTML icon using a Font Awesome snippet
{
label: "Education",
color: "#ff6283",
icon: {
html: `<span class="icon fa-solid fa-graduation-cap"></span>`
}
},
// An image icon
{
label: "Emergency services",
icon: {
url: "https://icons.flourish.studio/....png"
}
}
]
When creating an icon legend, also modify the settings that are exposed to the user to hide settings for normal swatches in favor of settings specifically for icons.
To do this, when importing the legend settings in your template.yml
file, use the
following overrides:
- property: icon_legend
import: "@flourish/legend/discrete-color"
overrides:
- property: icon_height
show_if: true
- property: icon_color
show_if: true
- property: swatch_width
show_if: false
- property: swatch_height
show_if: false
- property: swatch_radius
show_if: false
Continuous (color) legend
legend_continuous
.data(domain, colorScale)
.markerValue(500);
domain
is a 2-element array (e.g. [0, 1000]
) that specifies the values at the lower and upper end of the color scale. color_scale
is a color scale function (e.g. from the colors component). The markerValue
method adds a black and white marker centred on its argument's value. Pass in a value of null
to remove.
Continuous (size) legend
legend_size
.scale(sizeScale)
.symbolType("circle"|"spike")
.spikeWidth(number);
size_scale
is a scale function that maps the domain to a size. For example, if the legend is representing circle size, this would typically be a D3 scaleSqrt
.
It's assumed that the domain and range minima (e.g. size_scale.domain()[0]
) are zero to keep things simple and because this is good practice. (It's the equivalent of starting bar charts at zero.)
symbolType
specifies the symbol type. Currently circles ("circle"
) and spikes ("spike"
) (used in Projection Map) are supported.
spikeWidth
specifies the base width (px) of spikes (if selected).
If size_scale
depends on the container size (which in turn depends on the size of the legend) then .update()
will need to be called twice. The first call to set the height of the legend and the second call to update the legend content.
For example:
legend_size
.visible(true)
.update();
// Compute sizeScale (typically this will require calling chart-layout's update function)
legend_size
.scale(sizeScale)
.update();
Additional methods/options
legend.getContainer()
Gets the legend node element
legend.visible(true|false)
Sets the visibility of the legend.
legend.format(formatFunction)
Adds a formatter function to format the labels
legend.autoTitle(string)
Sets the automatic title for the legend. This could be a column name for example.
Multiple legend instances
A typical implementation of multiple legends might look something like:
template.yml
- Discrete color legend
- property: legend_categorical
import: "@flourish/legend/discrete-color"
- Continuous color legend
- property: legend_continuous
import: "@flourish/legend/continuous-color"
state.js
// Settings overrides
legend_categorical: {
title_mode: "custom"
},
legend_continuous: {
title_mode: "custom"
}
legend.js
const discrete_color_legend, continuous_color_legend;
function initLegends() {
discrete_color_legend = createDiscreteColorLegend(state.legend_categorical);
continuous_color_legend = createContinuousColorLegend(state.legend_continuous);
const legend_container = layout.getSection("legend");
discrete_color_legend.appendTo(legend_container);
continuous_color_legend.appendTo(legend_container);
}
function updateLegends() {
discrete_color_legend
.data(...)
.update();
continuous_color_legend
.data(...)
.update();
}
If a legend needs to change type, add a legend for each type and use .visible()
to hide/show such that one is showing at a time.