diff --git a/CHANGELOG.md b/CHANGELOG.md index 42a380b..b560f81 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,12 @@ Fixes x-scaling ratio when the SVG x-dimension is smaller than the available window. Now it scales with the window whereas before it scaled at twice the rate resulting in it being much smaller than necessary. +Adds the ability to drive the SVG background. New panelConfig terms: +- background.darkThemeColor +- background.lightThemeColor +Can be used with the normal color-names, rbg, hex values. When the relevant term is +undefined the background color is not driven. + ## 1.5.0 Fixes the grafana variable threshold matching to break out on first rule match for a given variable/cell tuple. Before it was continuing through diff --git a/provisioning/dashboardData/backgroundColor.svg b/provisioning/dashboardData/backgroundColor.svg new file mode 100644 index 0000000..a88a39b --- /dev/null +++ b/provisioning/dashboardData/backgroundColor.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/provisioning/dashboards/backgroundColor.json b/provisioning/dashboards/backgroundColor.json new file mode 100644 index 0000000..842ce3e --- /dev/null +++ b/provisioning/dashboards/backgroundColor.json @@ -0,0 +1,182 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 6, + "links": [], + "liveNow": false, + "panels": [ + { + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "gridPos": { + "h": 4, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 4, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "# Background\n\nBackground is normally left untouched but the panel yaml can define a darkTheme and a lightTheme color.\nIf the yaml field is present the background color is driven. Go to user -> profile to change the theme from dark to light.", + "mode": "markdown" + }, + "pluginVersion": "10.0.0", + "title": "Panel Title", + "type": "text" + }, + { + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 4 + }, + "id": 5, + "options": { + "debuggingCtr": { + "colorsCtr": 0, + "dataCtr": 0, + "displaySvgCtr": 0, + "mappingsCtr": 0, + "timingsCtr": 0 + }, + "siteConfig": "", + "svg": "\n\n\n", + "testDataEnabled": true, + "timeSliderEnabled": true + }, + "title": "Background Not driven", + "type": "andrewbmchugh-flow-panel" + }, + { + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 4 + }, + "id": 2, + "options": { + "debuggingCtr": { + "colorsCtr": 0, + "dataCtr": 0, + "displaySvgCtr": 0, + "mappingsCtr": 0, + "timingsCtr": 0 + }, + "panelConfig": "---\n\nbackground:\n darkThemeColor: \"yellow\"\n lightThemeColor: \"green\"", + "siteConfig": "", + "svg": "\n\n\n", + "testDataEnabled": true, + "timeSliderEnabled": true + }, + "title": "Background - darkTheme=yellow, lightTheme=green", + "type": "andrewbmchugh-flow-panel" + }, + { + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 13 + }, + "id": 7, + "options": { + "debuggingCtr": { + "colorsCtr": 0, + "dataCtr": 0, + "displaySvgCtr": 0, + "mappingsCtr": 0, + "timingsCtr": 0 + }, + "panelConfig": "---\n\nbackground:\n darkThemeColor: \"#0000ff\"\n lightThemeColor: \"#ff0000\"", + "siteConfig": "", + "svg": "\n\n\n", + "testDataEnabled": true, + "timeSliderEnabled": true + }, + "title": "Background - darkTheme=#0000ff, lightTheme=#ff0000", + "type": "andrewbmchugh-flow-panel" + }, + { + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 13 + }, + "id": 6, + "options": { + "debuggingCtr": { + "colorsCtr": 0, + "dataCtr": 0, + "displaySvgCtr": 0, + "mappingsCtr": 0, + "timingsCtr": 0 + }, + "panelConfig": "---\n\nbackground:\n darkThemeColor: \"rgb(0,0,255)\"\n lightThemeColor: \"rgb(255,0,0)\"", + "siteConfig": "", + "svg": "\n\n\n", + "testDataEnabled": true, + "timeSliderEnabled": true + }, + "title": "Background - darkTheme=rgb(0,0,255), lightTheme=rgb(255,0,0)", + "type": "andrewbmchugh-flow-panel" + } + ], + "refresh": "", + "schemaVersion": 38, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "Background Color", + "version": 12, + "weekStart": "" + } \ No newline at end of file diff --git a/src/components/Config.tsx b/src/components/Config.tsx index 20fc3d0..101394f 100644 --- a/src/components/Config.tsx +++ b/src/components/Config.tsx @@ -18,6 +18,11 @@ export type Link = { params: LinkUrlParams; }; +export type Background = { + darkThemeColor: string | undefined; + lightThemeColor: string | undefined; +} + export type PanelConfigCellLabel = { dataRef: string | undefined; separator: LabelSeparator; @@ -49,6 +54,7 @@ export type SiteConfig = { }; export type PanelConfig = { + background: Background; variableThresholdScalars: Map; gradientMode: ColorGradientMode; cellIdPreamble: string; @@ -60,6 +66,7 @@ export type PanelConfig = { export function panelConfigFactory(config: any) { config = config || {}; return { + background: config.background || {}, variableThresholdScalars: new Map(Object.entries(config.variableThresholdScalars || {})), gradientMode: config.gradientMode || 'none', cellIdPreamble: config.cellIdPreamble || '', diff --git a/src/components/FlowPanel.tsx b/src/components/FlowPanel.tsx index ed2a58e..21b6ee1 100644 --- a/src/components/FlowPanel.tsx +++ b/src/components/FlowPanel.tsx @@ -10,7 +10,7 @@ import { svgInit, svgUpdate, SvgHolder } from 'components/SvgUpdater'; import { seriesExtend, seriesInterpolate , seriesTransform } from 'components/TimeSeries'; import { TimeSliderFactory } from 'components/TimeSlider'; import { displayColorsInner, displayDataInner, displayMappingsInner, displaySvgInner } from 'components/DebuggingEditor'; -import { primeColorCache, appendUrlParams, getInstrumenter } from 'components/Utils'; +import { appendUrlParams, getInstrumenter } from 'components/Utils'; import { addHook, sanitize } from 'dompurify'; interface Props extends PanelProps {} @@ -133,8 +133,7 @@ export const FlowPanel: React.FC = ({ options, data, width, height, timeZ configInit(siteConfig, panelConfig); const svgDoc = new DOMParser().parseFromString(sanitizeSvgStr(svgStr), "text/xml"); - const svgAttribs = svgInit(svgDoc, panelConfig, siteConfig); - primeColorCache(grafanaTheme.current, svgAttribs); + const svgAttribs = svgInit(svgDoc, grafanaTheme.current, panelConfig, siteConfig); svgHolderRef.current = { doc: svgDoc, attribs: svgAttribs, diff --git a/src/components/SvgUpdater.tsx b/src/components/SvgUpdater.tsx index 24ef6da..30d8ea8 100644 --- a/src/components/SvgUpdater.tsx +++ b/src/components/SvgUpdater.tsx @@ -1,11 +1,12 @@ -import { getValueFormatterIndex, formattedValueToString } from '@grafana/data'; +import { getValueFormatterIndex, formattedValueToString, GrafanaTheme2 } from '@grafana/data'; import { LabelSeparator, Link, PanelConfig, PanelConfigCell, PanelConfigCellColor, PanelConfigCellLabel, SiteConfig, VariableThresholdScalars } from 'components/Config'; import { TimeSeriesData } from 'components/TimeSeries'; import { - cellIdFactory, CellIdMaker, getColor, + cellIdFactory, CellIdMaker, colorLookup, getColor, + primeColorCache, variableThresholdScalarsInit, variableThresholdScaleValue } from 'components/Utils'; // Defines the metadata stored against each drivable svg cell @@ -109,7 +110,7 @@ function recurseElements(el: HTMLElement, cellData: SvgCell, cellIdMaker: CellId return false; } -export function svgInit(doc: Document, panelConfig: PanelConfig, siteConfig: SiteConfig): SvgAttribs { +export function svgInit(doc: Document, grafanaTheme: GrafanaTheme2, panelConfig: PanelConfig, siteConfig: SiteConfig): SvgAttribs { let cells = new Map(); const cellIdPreamble = panelConfig.cellIdPreamble; panelConfig.cells.forEach((cellProps, cellIdShort) => { @@ -155,7 +156,9 @@ export function svgInit(doc: Document, panelConfig: PanelConfig, siteConfig: Sit // image won't scale and center corrently let dimensions = dimensionCoherence(doc); - return { + + + const svgAttribs = { width: dimensions.width, height: dimensions.height, scaleDrive: dimensions.scaleDrive, @@ -163,6 +166,17 @@ export function svgInit(doc: Document, panelConfig: PanelConfig, siteConfig: Sit elementLinks: elementLinks, variableValues: variableValues, }; + + // Initialie the color cache and setup the background + primeColorCache(grafanaTheme, svgAttribs, panelConfig.background); + + // Set background according to theme if defined in config + const bgColor = grafanaTheme.isDark ? panelConfig.background.darkThemeColor : panelConfig.background.lightThemeColor; + if (bgColor) { + doc.documentElement.style.backgroundColor = colorLookup(bgColor); + } + + return svgAttribs; } function getCellValue(tsName: string, tsData: TimeSeriesData) { diff --git a/src/components/Utils.tsx b/src/components/Utils.tsx index 76e749d..f6025e5 100644 --- a/src/components/Utils.tsx +++ b/src/components/Utils.tsx @@ -1,6 +1,6 @@ import { GrafanaTheme2, colorManipulator } from '@grafana/data'; import { SvgAttribs, SvgCell } from 'components/SvgUpdater' -import { PanelConfigCellColor, Threshold ,VariableThresholdScalars } from 'components/Config'; +import { Background, PanelConfigCellColor, Threshold ,VariableThresholdScalars } from 'components/Config'; @@ -66,7 +66,7 @@ function rgbToString(rgb: number[]) { return `rgb(${rgb[0]}, ${rgb[1]}, ${rgb[2]})`; } -export function primeColorCache(theme: GrafanaTheme2, svgAttribs: SvgAttribs) { +export function primeColorCache(theme: GrafanaTheme2, svgAttribs: SvgAttribs, background: Background) { function initCache(thresholds: Threshold[] | undefined) { if (thresholds) { thresholds.forEach(function(threshold) { @@ -79,6 +79,13 @@ export function primeColorCache(theme: GrafanaTheme2, svgAttribs: SvgAttribs) { initCache(cellData.cellProps.fillColor && cellData.cellProps.fillColor.thresholds); initCache(cellData.cellProps.labelColor && cellData.cellProps.labelColor.thresholds); }); + + if (background.darkThemeColor) { + colorStringToRgb(theme, background.darkThemeColor); + } + if (background.lightThemeColor) { + colorStringToRgb(theme, background.lightThemeColor); + } } export function colorStringToRgb(theme: GrafanaTheme2, colorStr: string) { diff --git a/yaml_defs/panelConfig.yaml b/yaml_defs/panelConfig.yaml index 9d3dece..2e6aaf0 100644 --- a/yaml_defs/panelConfig.yaml +++ b/yaml_defs/panelConfig.yaml @@ -30,6 +30,12 @@ variableThresholdScalars: #------------------------------------------------------------------------------ # Panel Config +# 1.6.0 onwards: When undefined the background color is not driven. When defined the color for +# the current theme is used. Colors can be entered in all the normal ways of name, hex, hsl, etc. +background: + darkThemeColor: "yellow" + lightThemeColor: "green" + # This defines the default color gradientMode. It defines the default value on cell labelColor.gradientMode # and fillColor.gradientMode for when the field is undefined. Values are "hue" and "none" with # "none" being the default when undefined.