react-plot
Version:
Library of React components to render SVG 2D plots.
128 lines • 7.42 kB
JavaScript
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { useContext, useEffect, useMemo } from 'react';
import { AlignGroup } from 'react-d3-utils';
import { useLegend } from '../contexts/legendContext.js';
import { legendOffsetContext } from '../contexts/legendOffsetContext.js';
import { usePlotContext, usePlotDispatchContext, } from '../contexts/plotContext.js';
import { functionalStyle } from '../utils.js';
import { markersMap } from './Markers.map.js';
function exclusiveProps(offsets, a, b, position) {
if (offsets[a] !== undefined) {
if (offsets[b] !== undefined) {
throw new Error(`${a} and ${b} should't be both defined for the position ${position}`);
}
return { key: a, value: offsets[a] };
}
return offsets[b] !== undefined ? { key: b, value: offsets[b] } : {};
}
function translation(position, legendOffsets, plotWidth, plotHeight, legendOffset) {
switch (position) {
case 'embedded': {
const { key: verticalKey = 'top', value: verticalValue = 10 } = exclusiveProps(legendOffsets, 'top', 'bottom', position);
const { key: horizontalKey = 'left', value: horizontalValue = 10 } = exclusiveProps(legendOffsets, 'left', 'right', position);
const x = horizontalKey === 'right'
? plotWidth - horizontalValue
: horizontalValue;
const y = verticalKey === 'bottom' ? plotHeight - verticalValue : verticalValue;
return {
x,
y,
horizontalAlign: horizontalKey === 'left' ? 'start' : 'end',
verticalAlign: verticalKey === 'top' ? 'start' : 'end',
};
}
case 'top': {
const { value: horizontalValue = plotWidth / 2 } = exclusiveProps(legendOffsets, 'left', 'right', position);
const x = horizontalValue;
const y = -(legendOffsets.bottom || 0) - legendOffset;
return { x, y, horizontalAlign: 'middle', verticalAlign: 'end' };
}
case 'right': {
const { key: verticalKey = 'top', value: verticalValue = plotHeight / 2, } = exclusiveProps(legendOffsets, 'top', 'bottom', position);
const y = verticalKey === 'bottom' ? -verticalValue : verticalValue;
const x = plotWidth + (legendOffsets.left || 0) + legendOffset;
return { x, y, horizontalAlign: 'start', verticalAlign: 'middle' };
}
case 'bottom': {
const { value: horizontalValue = plotWidth / 2 } = exclusiveProps(legendOffsets, 'left', 'right', position);
const x = horizontalValue;
const y = plotHeight + (legendOffsets.top || 0) + legendOffset;
return { x, y, horizontalAlign: 'middle', verticalAlign: 'start' };
}
case 'left': {
const { key: verticalKey = 'top', value: verticalValue = plotHeight / 2, } = exclusiveProps(legendOffsets, 'top', 'bottom', position);
const y = verticalKey === 'bottom' ? -verticalValue : verticalValue;
const x = -(legendOffsets.right || 0) - legendOffset;
return { x, y, horizontalAlign: 'end', verticalAlign: 'middle' };
}
default: {
throw new Error(`Position ${JSON.stringify(position)} unknown`);
}
}
}
export function Legend(options) {
const { position = 'embedded', margin = 10, onClick, lineStyle: funcLineStyle = {}, showHide = false, labelStyle: funcLabelStyle = {}, ...legendOffsets } = options;
const { plotWidth, plotHeight } = usePlotContext();
const plotDispatch = usePlotDispatchContext();
const [state, legendDispatch] = useLegend();
const legendOffset = useContext(legendOffsetContext);
const alignGroupProps = useMemo(() => {
return translation(position, legendOffsets, plotWidth, plotHeight, legendOffset);
}, [position, legendOffsets, plotWidth, plotHeight, legendOffset]);
useEffect(() => {
plotDispatch({ type: 'addLegend', payload: { position, margin } });
return () => plotDispatch({ type: 'removeLegend' });
}, [plotDispatch, position, margin]);
function onClickLegendItem(event, id) {
onClick?.({ event, id });
if (showHide) {
legendDispatch({
type: 'TOGGLE_VISIBILITY',
payload: { id },
});
}
}
return (_jsx(AlignGroup, { ...alignGroupProps, children: state.labels.map((value, index) => {
const labelStyle = functionalStyle({ fontSize: '16px' }, funcLabelStyle, { id: value.id });
const lineStyle = functionalStyle({}, funcLineStyle, { id: value.id });
// TODO: fix this as it's not guaranteed that `fontSize` can be parsed as a string.
const height = Number.parseInt(String(labelStyle.fontSize), 10);
const xPos = 10;
const yPos = index * height + height / 2 + 3;
if (value.range) {
return (_jsxs("g", { onClick: (event) => onClickLegendItem(event, value.id), transform: `translate(${xPos}, 0)`, style: { opacity: value.isVisible ? '1' : '0.6' }, children: [getRangeShape({
index,
rangeColor: value.range.rangeColor,
lineColor: value.colorLine,
style: lineStyle,
height,
}), _jsx("text", { style: labelStyle, x: 30, y: `${(index + 1) * height}`, children: value.label })] }, index));
}
let Marker;
if (value.shape) {
Marker = markersMap[value.shape.figure];
}
return (_jsxs("g", { onClick: (event) => onClickLegendItem(event, value.id), transform: `translate(${xPos}, 0)`, style: { opacity: value.isVisible ? '1' : '0.6' }, children: [getLineShape({
index,
color: value.colorLine,
style: lineStyle,
height,
}), _jsx("g", { transform: `translate(${xPos - 1}, ${yPos})`, children: value.shape && Marker && !value.shape.hidden && (_jsx(Marker, { size: 10, style: { fill: value.shape.color } })) }), _jsx("text", { style: labelStyle, x: 30, y: `${(index + 1) * height}`, children: value.label })] }, index));
}) }));
}
function getLineShape(config) {
const { index, color, style = {}, height = 16 } = config;
const x = 0;
const { strokeWidth = '2px' } = style;
const y = index * height + height / 2 + 3;
return (_jsx("line", { x1: x, x2: x + 20, y1: y, y2: y, stroke: color, style: { ...style, strokeWidth } }));
}
function getRangeShape(config) {
const { index, rangeColor, lineColor, style = {}, height = 16 } = config;
const { strokeWidth = '15px' } = style;
const lineHeight = Number.parseInt(strokeWidth?.toString(), 10) / 5;
const x = 0;
const y = index * height + height / 2 - lineHeight;
return (_jsxs("g", { transform: `translate(${x}, ${y})`, children: [_jsx("rect", { width: "20", height: lineHeight * 3, fill: rangeColor }), _jsx("line", { style: style, x1: 0, y: 0, x2: 20, y2: 0, stroke: lineColor, strokeWidth: lineHeight }), _jsx("line", { style: style, x1: 0, y1: lineHeight * 3, x2: 20, y2: lineHeight * 3, stroke: lineColor, strokeWidth: lineHeight })] }));
}
//# sourceMappingURL=Legend.js.map