mirror of
https://github.com/grafana/grafana.git
synced 2025-09-17 22:35:29 +08:00
VizLayout: Simple viz layout component for legend placement and scaling (#28820)
* Updates * Updated * Rename slot to legend * Updated * Adding js doc comments * hide horizontal track * Fix docs error * Added another export * removing auto mode * I hate these doc warnings
This commit is contained in:
@ -0,0 +1,66 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { withCenteredStory } from '../../utils/storybook/withCenteredStory';
|
||||||
|
import { number } from '@storybook/addon-knobs';
|
||||||
|
import { VizLayout } from './VizLayout';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: 'Visualizations/VizLayout',
|
||||||
|
component: VizLayout,
|
||||||
|
decorators: [withCenteredStory],
|
||||||
|
parameters: {
|
||||||
|
docs: {},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const getKnobs = () => {
|
||||||
|
return {
|
||||||
|
legendWidth: number('legendWidth', 100),
|
||||||
|
legendItems: number('legendItems', 2),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const BottomLegend = () => {
|
||||||
|
const { legendItems } = getKnobs();
|
||||||
|
const items = Array.from({ length: legendItems }, (_, i) => i + 1);
|
||||||
|
|
||||||
|
const legend = (
|
||||||
|
<VizLayout.Legend position="bottom" maxHeight="30%">
|
||||||
|
{items.map((_, index) => (
|
||||||
|
<div style={{ height: '30px', width: '100%', background: 'blue', marginBottom: '2px' }}>
|
||||||
|
Legend item {index}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</VizLayout.Legend>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<VizLayout width={400} height={500} legend={legend}>
|
||||||
|
{(vizWidth: number, vizHeight: number) => {
|
||||||
|
return <div style={{ width: vizWidth, height: vizHeight, background: 'red' }} />;
|
||||||
|
}}
|
||||||
|
</VizLayout>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const RightLegend = () => {
|
||||||
|
const { legendItems, legendWidth } = getKnobs();
|
||||||
|
const items = Array.from({ length: legendItems }, (_, i) => i + 1);
|
||||||
|
|
||||||
|
const legend = (
|
||||||
|
<VizLayout.Legend position="right" maxWidth="50%">
|
||||||
|
{items.map((_, index) => (
|
||||||
|
<div style={{ height: '30px', width: `${legendWidth}px`, background: 'blue', marginBottom: '2px' }}>
|
||||||
|
Legend item {index}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</VizLayout.Legend>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<VizLayout width={400} height={500} legend={legend}>
|
||||||
|
{(vizWidth: number, vizHeight: number) => {
|
||||||
|
return <div style={{ width: vizWidth, height: vizHeight, background: 'red' }} />;
|
||||||
|
}}
|
||||||
|
</VizLayout>
|
||||||
|
);
|
||||||
|
};
|
99
packages/grafana-ui/src/components/VizLayout/VizLayout.tsx
Normal file
99
packages/grafana-ui/src/components/VizLayout/VizLayout.tsx
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
import React, { FC, CSSProperties, ComponentType } from 'react';
|
||||||
|
import { useMeasure } from 'react-use';
|
||||||
|
import CustomScrollbar from '../CustomScrollbar/CustomScrollbar';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @beta
|
||||||
|
*/
|
||||||
|
export interface VizLayoutProps {
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
legend?: React.ReactElement<VizLayoutLegendProps>;
|
||||||
|
children: (width: number, height: number) => React.ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @beta
|
||||||
|
*/
|
||||||
|
export interface VizLayoutComponentType extends FC<VizLayoutProps> {
|
||||||
|
Legend: ComponentType<VizLayoutLegendProps>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @beta
|
||||||
|
*/
|
||||||
|
export const VizLayout: VizLayoutComponentType = ({ width, height, legend, children }) => {
|
||||||
|
const containerStyle: CSSProperties = {
|
||||||
|
display: 'flex',
|
||||||
|
width: `${width}px`,
|
||||||
|
height: `${height}px`,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!legend) {
|
||||||
|
return <div style={containerStyle}>{children(width, height)}</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { position, maxHeight, maxWidth } = legend.props;
|
||||||
|
const [legendRef, legendMeasure] = useMeasure();
|
||||||
|
let size: VizSize | null = null;
|
||||||
|
|
||||||
|
const vizStyle: CSSProperties = {
|
||||||
|
flexGrow: 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
const legendStyle: CSSProperties = {
|
||||||
|
flexGrow: 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (position) {
|
||||||
|
case 'bottom':
|
||||||
|
containerStyle.flexDirection = 'column';
|
||||||
|
legendStyle.maxHeight = maxHeight;
|
||||||
|
|
||||||
|
if (legendMeasure) {
|
||||||
|
size = { width, height: height - legendMeasure.height };
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'right':
|
||||||
|
containerStyle.flexDirection = 'row';
|
||||||
|
legendStyle.maxWidth = maxWidth;
|
||||||
|
|
||||||
|
if (legendMeasure) {
|
||||||
|
size = { width: width - legendMeasure.width, height };
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div style={containerStyle}>
|
||||||
|
<div style={vizStyle}>{size && children(size.width, size.height)}</div>
|
||||||
|
<div style={legendStyle} ref={legendRef}>
|
||||||
|
<CustomScrollbar hideHorizontalTrack>{legend}</CustomScrollbar>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
interface VizSize {
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @beta
|
||||||
|
*/
|
||||||
|
export interface VizLayoutLegendProps {
|
||||||
|
position: 'bottom' | 'right';
|
||||||
|
maxHeight?: string;
|
||||||
|
maxWidth?: string;
|
||||||
|
children: React.ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @beta
|
||||||
|
*/
|
||||||
|
export const VizLayoutLegend: FC<VizLayoutLegendProps> = ({ children }) => {
|
||||||
|
return <>{children}</>;
|
||||||
|
};
|
||||||
|
|
||||||
|
VizLayout.Legend = VizLayoutLegend;
|
@ -78,6 +78,7 @@ export { BarGauge, BarGaugeDisplayMode } from './BarGauge/BarGauge';
|
|||||||
export { GraphTooltipOptions } from './Graph/GraphTooltip/types';
|
export { GraphTooltipOptions } from './Graph/GraphTooltip/types';
|
||||||
export { VizRepeater, VizRepeaterRenderValueProps } from './VizRepeater/VizRepeater';
|
export { VizRepeater, VizRepeaterRenderValueProps } from './VizRepeater/VizRepeater';
|
||||||
export { graphTimeFormat, graphTickFormatter } from './Graph/utils';
|
export { graphTimeFormat, graphTickFormatter } from './Graph/utils';
|
||||||
|
export { VizLayout, VizLayoutComponentType, VizLayoutLegendProps, VizLayoutProps } from './VizLayout/VizLayout';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
LegendOptions,
|
LegendOptions,
|
||||||
|
Reference in New Issue
Block a user