| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081 |
- import {rgb} from "d3";
- import {createContext} from "./context.js";
- import {legendRamp} from "./legends/ramp.js";
- import {legendSwatches, legendSymbols} from "./legends/swatches.js";
- import {inherit, isScaleOptions} from "./options.js";
- import {normalizeScale} from "./scales.js";
- const legendRegistry = new Map([
- ["symbol", legendSymbols],
- ["color", legendColor],
- ["opacity", legendOpacity]
- ]);
- export function legend(options = {}) {
- for (const [key, value] of legendRegistry) {
- const scale = options[key];
- if (isScaleOptions(scale)) {
- // e.g., ignore {color: "red"}
- const context = createContext(options);
- let hint;
- // For symbol legends, pass a hint to the symbol scale.
- if (key === "symbol") {
- const {fill, stroke = fill === undefined && isScaleOptions(options.color) ? "color" : undefined} = options;
- hint = {fill, stroke};
- }
- return value(normalizeScale(key, scale, hint), legendOptions(context, scale, options), (key) =>
- isScaleOptions(options[key]) ? normalizeScale(key, options[key]) : null
- );
- }
- }
- throw new Error("unknown legend type; no scale found");
- }
- export function exposeLegends(scales, context, defaults = {}) {
- return (key, options) => {
- if (!legendRegistry.has(key)) throw new Error(`unknown legend type: ${key}`);
- if (!(key in scales)) return;
- return legendRegistry.get(key)(scales[key], legendOptions(context, defaults[key], options), (key) => scales[key]);
- };
- }
- function legendOptions({className, ...context}, {label, ticks, tickFormat} = {}, options) {
- return inherit(options, {className, ...context}, {label, ticks, tickFormat});
- }
- function legendColor(color, {legend = true, ...options}) {
- if (legend === true) legend = color.type === "ordinal" ? "swatches" : "ramp";
- if (color.domain === undefined) return; // no identity legend
- switch (`${legend}`.toLowerCase()) {
- case "swatches":
- return legendSwatches(color, options);
- case "ramp":
- return legendRamp(color, options);
- default:
- throw new Error(`unknown legend type: ${legend}`);
- }
- }
- function legendOpacity({type, interpolate, ...scale}, {legend = true, color = rgb(0, 0, 0), ...options}) {
- if (!interpolate) throw new Error(`${type} opacity scales are not supported`);
- if (legend === true) legend = "ramp";
- if (`${legend}`.toLowerCase() !== "ramp") throw new Error(`${legend} opacity legends are not supported`);
- return legendColor({type, ...scale, interpolate: interpolateOpacity(color)}, {legend, ...options});
- }
- function interpolateOpacity(color) {
- const {r, g, b} = rgb(color) || rgb(0, 0, 0); // treat invalid color as black
- return (t) => `rgba(${r},${g},${b},${t})`;
- }
- export function createLegends(scales, context, options) {
- const legends = [];
- for (const [key, value] of legendRegistry) {
- const o = options[key];
- if (o?.legend && key in scales) {
- const legend = value(scales[key], legendOptions(context, scales[key], o), (key) => scales[key]);
- if (legend != null) legends.push(legend);
- }
- }
- return legends;
- }
|