Security News
Oracle Drags Its Feet in the JavaScript Trademark Dispute
Oracle seeks to dismiss fraud claims in the JavaScript trademark dispute, delaying the case and avoiding questions about its right to the name.
@flourish/info-popup
Advanced tools
Add data-driven popups (tooltips) and panels to any Flourish template, with style settings.
There are typically seven steps to using the module:
npm install @flourish/info-popup
const state = {
popup: {} // Add any properties to this object to override the default settings
}
template.yml
file - Popups & panels
- property: popup
import: "@flourish/info-popup"
Initialize the popup, passing in the state property and optionally containers that determine the position of the popups and panels
import initialisePopup from "@flourish/info-popup";
const popup = initialisePopup(state.popup, panel_container, popup_container);
If you want the panel to fill the whole page (i.e. cover the header & footer), just ignore the panel_container
and popup_container
arguments.
The important thing to understand with this module is that the template passes on information about user triggered events (e.g. click, mouseover etc) and then the module decides what should happen as a result of this event. This is because there are many different ways that popups and panels behave in response to user events depending on the settings selected. For example here are some of the different scenarios for the mouseover
event:
Always show
turned on: content loads in panelAlways show
turned on, with sticky content: nothing happensSo for consistency this logic is abstracted from the template. This is why there is no method for actions such as opening a popup because instead we call popup.mouseover()
and let the module look at all the different settings and decide what should happen as a result of that event.
All event based methods are listed below in the methods section but a common implementation will look something like this:
import { popup } from "./popup";
function updateGraphic() {
d3.selectAll(...) // datapoints
.on("mouseover", function() {
const el = this;
popup.mouseover(el, el.__data__);
})
.on("mouseout", function() {
popup.mouseout();
})
.on("click", function() {
const el = this;
const data = el.__data__
const locked_id = data.id
popup.click(el, data, locked_id); // See step 8 for more information on locked_id
});
}
.setColumnNames()
and .setFormatters()
For each popup we want to make sure we're displaying the correct labels and formatted values from the data. There are two parts to making this work:
This happens as part of step 5 when passing data in to popup.click
, popup.mouseover
or popup.touch
. You pass in the data that is bound to the node that you are interacting with. If you had the following data bindings: binding_one
,binding_two
, binding_three
and binding_four
the data on each data point (and therefore the data you would be passing to the popup module) would look something like this:
{
binding_one: "Joe Biden",
binding_two: "President",
binding_three: "https://public.flourish.studio/uploads/ff3f9984-470c-4ed9-beb8-2a86bb7019ea.jpg",
binding_four: "Democrat"
}
Currently the popup has been passed a set of values that correlate to data bindings, we now have to set a column name for each data binding we wish to appear in the popup:
popup
.setColumnNames({
binding_one: "Name",
binding_two: "Job title",
binding_four: "Party"
})
.update()
Data will only show if we have set a column name for that data binding. We didnt set a column name for binding_three
so the resulting information displayed in the popup would be:
Name: Joe Biden
Job title: President
Party: Democrat
If there are no columns that you wish to exclude you can pass in the column_names
object from the Flourish dataset:
popup
.setColumnNames(data.data.column_names)
.update()
If there are columns you'd like to be available for custom content, but don't want to show in the default popup or panel content (eg. long series data), you can exclude them using .hideColumnNames()
. This takes an array of binding names. In the above example, calling .hideColumnNames(["binding_four"])
will not show the Party information in the default popup or panel.
Optionally, you can also set formatters for each data binding. These must match the data bindings passed in .setColumnNames()
but you do not need to provide a formatter for all bindings.
Formatters take two forms:
initNumberFormatter
in @flourish/formatters should by passed like this so that formatting changes in the settings panel are reflected in the popup.output_format_id
string property used in the [@flourish/interpreter] module. This is passed to @flourish/formatters to generate a formatter function.For multi-column bindings you can pass in an array of formatters (where each formatter is a function or an object containing output_format_id
).
popup
.setColumnNames({
binding_one: "Name",
binding_two: "Cost",
binding_three: "Sold",
binding_four: "Released"
})
.setFormatters({
binding_two: d => `£${d}`,
binding_three: { output_format_id: "number$comma_point" }
binding_four: { output_format_id: "datetime$%d/%m/%Y" },
})
.update()
If the data below was passed to the popup:
{
binding_one: "Pain au chocolat",
binding_two: 2,
binding_three: 1235000,
binding_four: new Date("2022-05-12T03:24:00")
}
The resulting information would be displayed in the popup:
Name: Pain au chocolat
Cost: £2
Sold: 1,235,000
Released: 05/12/2022
If you do not want to pass any custom formatter functions you can set formatters for all bindings by passing the metadata
object for a dataset. This object includes entries with an output_format_id
string property for each binding (these can be set by the user in the data panel).
popup
.setColumnNames(data.data.column_names)
.setFormatters(data.data.metadata)
.update()
.update()
To make sure that the popup is using the latest settings, adds the correct content based on what's passed in via .setColumnNames()
, we need to call popup.update()
inside the template's update()
loop.
Locked functionality is the ability to 'lock' a popup in an open state. A locked popup will remain open until clickout
is triggered and while locked it will have CSS pointer events enabled, so that the end viewer can for example click a link inside the popup.
To set up locking functionality you need to define a getLockedPosition
function. If there is a locked popup this function will retreive the locked node or coordinate information of the locked item, and the data that's associated with it. It returns an array: [node_or_coordinate, data]
This function needs only be called once so can be called straight after the popup is initialised, but can also be called as part of an update function.
popup.getLockedPosition(getLockedPositionCallback)
function getLockedPositionCallback(locked_id) {
// get the node that relates to this id (this is just one common way you might do this)
const el_node = select(`#${locked_id}`).node();
// if there is no locked popup, or there is currently no element on the screen
// corresponding to the stored locked popup return null
if (!el_node) return null;
// get the data from that node
const datum = el_node && el_node.__data__;
// return node and data
return [el_node, datum];
}
popup.click(coords_or_node, data, locked_id, callback)
Used when the viewer clicks a data point. coords_or_node
can be a coordinate array ([x, y]) or an DOM element. data
is the data to display (usually the data attached to the element you are clicking). locked_id
is an identifier for the clicked data point. If locked_id
is undefined it wont be locked, if it is defined the value will be stored as the locked_id and passed to the getLockedPositionCallback
function.
popup.mouseover(coords_or_node, data, callback)
Used when the viewer mouseovers a data point. (Note: this doesn't take the locked_id
argument since you can never lock a popup by mousing over a data point.)
popup.touch(coords_or_node, data, locked_id, callback)
Used when the viewer is on a touch device and touches a data point. It has the same behavior as mouseover except that in "Both" mode it makes it possible to touch once to open a popup and then touch the popup to open the panel. (Hence it needs the locked_id argument since this second touch locks the panel open.)
popup.mouseout()
Used when the viewer mouse leaves a data point. It closes or resets the popup or panel unless it is locked.
popup.clickout()
Used when the viewer clicks on something that isnt a data point. It closes the popup if it's locked; typically used in a click handler for the background (e.g. an SVG or canvas element). Note: this method can make code look quite counterintuitive e.g:
document.body.onclick = function() { popups.clickout(); };
This is because to the browser you are clicking but to the popups you are clicking out (because you are clicking on something that isnt a data point).
It's possible to specify that certain keys in the data represent the title and subtitle for the popup or panel. These appear in the header section of the popup with different styling from the rest of the popup.
popup.titleKey(data_binding_name)
popup.subtitleKey(data_binding_name)
You can specify a different template for the popup or panel content, for instance if you want to add an <img>
tag or the content needs to be shown in a specific order. This is done when initializing:
popup.popupDefaultTemplate(template_string)
popup.panelDefaultTemplate(template_string)
The template_string
can include data binding keys between curly brackets, such as <h1>{{name}}</h1>
where name
is your data binding.
popup.popupDirections(directions)
– gets or sets the popup directions.popup.margins()
– gets the space on the visualisation edges being used for the panel. This is useful for when you don't want the panel to overlay over the content.popup.hidePopup()
will hide the popup without resetting the locked_id
.popup.hidePanel()
will hide the panel without resetting the locked_id
.popup.locked()
– gets the current locked_id
from the popup state. Returns null
if there is currently no popup "locked" open.popup.mode()
– gets the current mode
from the popup state.popup.onPanelClose(fn)
will fire when the panel gets closedOn default, all data bindings are used as little buttons below the custom content setting. You can change this by adding a setting override:
overrides:
- property: [ popup_custom_main, popup_custom_header ]
editor:
style: true
url: true
flourish_embed: true
bindings: [ dataset_name.databinding_name_1, dataset_name.databinding_name_2 ]
Templates that use info-popups
in a fairly straightforward way inculde:
A template that uses info-popups
with canvas include:
If a template has multiple datasheets you will need to pass in the name of the datasheet that the info popup binding relates to. If it is not passed in the tests will use the first datasheet in the column_names
object.
FAQs
Popup with data insertion
The npm package @flourish/info-popup receives a total of 144 weekly downloads. As such, @flourish/info-popup popularity was classified as not popular.
We found that @flourish/info-popup demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Oracle seeks to dismiss fraud claims in the JavaScript trademark dispute, delaying the case and avoiding questions about its right to the name.
Security News
The Linux Foundation is warning open source developers that compliance with global sanctions is mandatory, highlighting legal risks and restrictions on contributions.
Security News
Maven Central now validates Sigstore signatures, making it easier for developers to verify the provenance of Java packages.