import { css } from '@emotion/css'; import { isString } from 'lodash'; import React, { CSSProperties } from 'react'; import SVG from 'react-inlinesvg'; import { ColorDimensionConfig, ResourceDimensionConfig, ResourceDimensionMode, getPublicOrAbsoluteUrl, } from 'app/features/dimensions'; import { DimensionContext } from 'app/features/dimensions/context'; import { ColorDimensionEditor, ResourceDimensionEditor } from 'app/features/dimensions/editors'; import { APIEditor, APIEditorConfig, callApi } from 'app/plugins/panel/canvas/editor/APIEditor'; import { CanvasElementItem, CanvasElementProps } from '../element'; import { LineConfig } from '../types'; export interface IconConfig { path?: ResourceDimensionConfig; fill?: ColorDimensionConfig; stroke?: LineConfig; api?: APIEditorConfig; } interface IconData { path: string; fill: string; strokeColor?: string; stroke?: number; api?: APIEditorConfig; } // When a stoke is defined, we want the path to be in page units const svgStrokePathClass = css` path { vector-effect: non-scaling-stroke; } `; export function IconDisplay(props: CanvasElementProps) { const { data } = props; if (!data?.path) { return null; } const onClick = () => { if (data?.api) { callApi(data.api); } }; const svgStyle: CSSProperties = { fill: data?.fill, stroke: data?.strokeColor, strokeWidth: data?.stroke, }; return ( ); } export const iconItem: CanvasElementItem = { id: 'icon', name: 'Icon', description: 'SVG Icon display', display: IconDisplay, getNewOptions: (options) => ({ placement: { width: 50, height: 50, top: 0, left: 0, }, ...options, config: { path: { mode: ResourceDimensionMode.Fixed, fixed: 'img/icons/unicons/question-circle.svg', }, fill: { fixed: '#FFF899' }, }, }), // Called when data changes prepareData: (ctx: DimensionContext, cfg: IconConfig) => { let path: string | undefined = undefined; if (cfg.path) { path = ctx.getResource(cfg.path).value(); } if (!path || !isString(path)) { path = getPublicOrAbsoluteUrl('img/icons/unicons/question-circle.svg'); } const data: IconData = { path, fill: cfg.fill ? ctx.getColor(cfg.fill).value() : '#CCC', api: cfg?.api ?? undefined, }; if (cfg.stroke?.width && cfg.stroke.color) { if (cfg.stroke.width > 0) { data.stroke = cfg.stroke?.width; data.strokeColor = ctx.getColor(cfg.stroke.color).value(); } } return data; }, // Heatmap overlay options registerOptionsUI: (builder) => { const category = ['Icon']; builder .addCustomEditor({ category, id: 'iconSelector', path: 'config.path', name: 'SVG Path', editor: ResourceDimensionEditor, settings: { resourceType: 'icon', }, }) .addCustomEditor({ category, id: 'config.fill', path: 'config.fill', name: '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), }) .addCustomEditor({ category, id: 'apiSelector', path: 'config.api', name: 'API', editor: APIEditor, }); }, };