mirror of
https://github.com/grafana/grafana.git
synced 2025-07-31 06:32:17 +08:00
166 lines
4.5 KiB
TypeScript
166 lines
4.5 KiB
TypeScript
import { css } from '@emotion/css';
|
|
import { isString } from 'lodash';
|
|
import { CSSProperties } from 'react';
|
|
|
|
import { LinkModel } from '@grafana/data';
|
|
import { t } from '@grafana/i18n';
|
|
import { ColorDimensionConfig, ResourceDimensionConfig, ResourceDimensionMode } from '@grafana/schema';
|
|
import { SanitizedSVG } from 'app/core/components/SVG/SanitizedSVG';
|
|
import { getPublicOrAbsoluteUrl } from 'app/features/dimensions';
|
|
import { DimensionContext } from 'app/features/dimensions/context';
|
|
import { ColorDimensionEditor, ResourceDimensionEditor } from 'app/features/dimensions/editors';
|
|
import { LineConfig } from 'app/plugins/panel/canvas/panelcfg.gen';
|
|
|
|
import { CanvasElementItem, CanvasElementOptions, CanvasElementProps, defaultBgColor } from '../element';
|
|
|
|
export interface IconConfig {
|
|
path?: ResourceDimensionConfig;
|
|
fill?: ColorDimensionConfig;
|
|
stroke?: LineConfig;
|
|
}
|
|
|
|
interface IconData {
|
|
path: string;
|
|
fill: string;
|
|
strokeColor?: string;
|
|
stroke?: number;
|
|
links?: LinkModel[];
|
|
}
|
|
|
|
// When a stoke is defined, we want the path to be in page units
|
|
const svgStrokePathClass = css({
|
|
path: {
|
|
vectorEffect: 'non-scaling-stroke',
|
|
},
|
|
});
|
|
|
|
export function IconDisplay(props: CanvasElementProps<IconConfig, IconData>) {
|
|
const { data } = props;
|
|
if (!data?.path) {
|
|
return null;
|
|
}
|
|
|
|
const svgStyle: CSSProperties = {
|
|
fill: data?.fill,
|
|
stroke: data?.strokeColor,
|
|
strokeWidth: data?.stroke,
|
|
height: '100%',
|
|
width: '100%',
|
|
};
|
|
|
|
return (
|
|
<SanitizedSVG src={data.path} style={svgStyle} className={svgStyle.strokeWidth ? svgStrokePathClass : undefined} />
|
|
);
|
|
}
|
|
|
|
export const iconItem: CanvasElementItem<IconConfig, IconData> = {
|
|
id: 'icon',
|
|
name: 'Icon',
|
|
description: 'SVG Icon display',
|
|
|
|
display: IconDisplay,
|
|
|
|
getNewOptions: (options) => ({
|
|
...options,
|
|
config: {
|
|
path: {
|
|
mode: ResourceDimensionMode.Fixed,
|
|
fixed: 'img/icons/unicons/question-circle.svg',
|
|
},
|
|
fill: { fixed: defaultBgColor },
|
|
},
|
|
background: {
|
|
color: {
|
|
fixed: 'transparent',
|
|
},
|
|
},
|
|
placement: {
|
|
width: options?.placement?.width ?? 100,
|
|
height: options?.placement?.height ?? 100,
|
|
top: options?.placement?.top ?? 100,
|
|
left: options?.placement?.left ?? 100,
|
|
rotation: options?.placement?.rotation ?? 0,
|
|
},
|
|
links: options?.links ?? [],
|
|
}),
|
|
|
|
// Called when data changes
|
|
prepareData: (dimensionContext: DimensionContext, elementOptions: CanvasElementOptions<IconConfig>) => {
|
|
const iconConfig = elementOptions.config;
|
|
|
|
let path: string | undefined = undefined;
|
|
if (iconConfig?.path) {
|
|
path = dimensionContext.getResource(iconConfig.path).value();
|
|
}
|
|
if (!path || !isString(path)) {
|
|
path = getPublicOrAbsoluteUrl('img/icons/unicons/question-circle.svg');
|
|
}
|
|
|
|
const data: IconData = {
|
|
path,
|
|
fill: iconConfig?.fill ? dimensionContext.getColor(iconConfig.fill).value() : defaultBgColor,
|
|
};
|
|
|
|
if (iconConfig?.stroke?.width && iconConfig?.stroke.color) {
|
|
if (iconConfig.stroke.width > 0) {
|
|
data.stroke = iconConfig.stroke?.width;
|
|
data.strokeColor = dimensionContext.getColor(iconConfig.stroke.color).value();
|
|
}
|
|
}
|
|
|
|
return data;
|
|
},
|
|
|
|
// Heatmap overlay options
|
|
registerOptionsUI: (builder) => {
|
|
const category = [t('canvas.icon-item.category-icon', 'Icon')];
|
|
builder
|
|
.addCustomEditor({
|
|
category,
|
|
id: 'iconSelector',
|
|
path: 'config.path',
|
|
name: t('canvas.icon-item.name-svg-path', 'SVG Path'),
|
|
editor: ResourceDimensionEditor,
|
|
settings: {
|
|
resourceType: 'icon',
|
|
maxFiles: 2000,
|
|
},
|
|
})
|
|
.addCustomEditor({
|
|
category,
|
|
id: 'config.fill',
|
|
path: 'config.fill',
|
|
name: t('canvas.icon-item.name-fill-color', 'Fill color'),
|
|
editor: ColorDimensionEditor,
|
|
settings: {},
|
|
defaultValue: {
|
|
// Configured values
|
|
fixed: 'grey',
|
|
},
|
|
});
|
|
// .addSliderInput({
|
|
// category,
|
|
// path: 'config.stroke.width',
|
|
// name: 'Stroke',
|
|
// defaultValue: 0,
|
|
// settings: {
|
|
// min: 0,
|
|
// max: 10,
|
|
// },
|
|
// })
|
|
// .addCustomEditor({
|
|
// category,
|
|
// id: 'config.stroke.color',
|
|
// path: 'config.stroke.color',
|
|
// name: 'Stroke color',
|
|
// editor: ColorDimensionEditor,
|
|
// settings: {},
|
|
// defaultValue: {
|
|
// // Configured values
|
|
// fixed: 'grey',
|
|
// },
|
|
// showIf: (cfg) => Boolean(cfg?.config?.stroke?.width),
|
|
// })
|
|
},
|
|
};
|