mirror of https://github.com/grafana/grafana.git
				
				
				
			Rendering arrows for color picker, applying color changes to time series
This commit is contained in:
		
							parent
							
								
									e35e266c81
								
							
						
					
					
						commit
						c8ac23f3c1
					
				|  | @ -2,9 +2,9 @@ import React, { Component, createRef } from 'react'; | |||
| import PopperController from '../Tooltip/PopperController'; | ||||
| import Popper from '../Tooltip/Popper'; | ||||
| import { ColorPickerPopover } from './ColorPickerPopover'; | ||||
| import { Themeable } from '../../types'; | ||||
| import { Themeable, GrafanaTheme } from '../../types'; | ||||
| 
 | ||||
| export interface ColorPickerProps { | ||||
| export interface ColorPickerProps extends Themeable { | ||||
|   color: string; | ||||
|   onChange: (color: string) => void; | ||||
| } | ||||
|  | @ -13,13 +13,29 @@ export class ColorPicker extends Component<ColorPickerProps & Themeable, any> { | |||
|   private pickerTriggerRef = createRef<HTMLDivElement>(); | ||||
| 
 | ||||
|   render() { | ||||
|     const { theme } = this.props; | ||||
|     return ( | ||||
|       <PopperController content={<ColorPickerPopover {...this.props} />}> | ||||
|       <PopperController placement="bottom-start"  content={<ColorPickerPopover {...this.props} />}> | ||||
|         {(showPopper, hidePopper, popperProps) => { | ||||
|           return ( | ||||
|             <> | ||||
|               {this.pickerTriggerRef.current && ( | ||||
|                 <Popper {...popperProps} referenceElement={this.pickerTriggerRef.current} className="ColorPicker" /> | ||||
|                 <Popper | ||||
|                   {...popperProps} | ||||
|                   referenceElement={this.pickerTriggerRef.current} | ||||
|                   className="ColorPicker" | ||||
|                   renderArrow={({ arrowProps, placement }) => { | ||||
|                     return ( | ||||
|                       <div | ||||
|                         {...arrowProps} | ||||
|                         data-placement={placement} | ||||
|                         className={`ColorPicker__arrow ColorPicker__arrow--${ | ||||
|                           theme === GrafanaTheme.Light ? 'light' : 'dark' | ||||
|                         }`}
 | ||||
|                       /> | ||||
|                     ); | ||||
|                   }} | ||||
|                 /> | ||||
|               )} | ||||
|               <div ref={this.pickerTriggerRef} onClick={showPopper} className="sp-replacer sp-light"> | ||||
|                 <div className="sp-preview"> | ||||
|  |  | |||
|  | @ -1,7 +1,7 @@ | |||
| import React from 'react'; | ||||
| import NamedColorsPicker from './NamedColorsPicker'; | ||||
| import NamedColorsPicker from './NamedColorsPalette'; | ||||
| import { getColorName } from '../..//utils/colorsPalette'; | ||||
| import { SpectrumPicker } from './SpectrumPicker'; | ||||
| import { SpectrumPalette } from './SpectrumPalette'; | ||||
| import { ColorPickerProps } from './ColorPicker'; | ||||
| import { GrafanaTheme, Themeable } from '../../types'; | ||||
| 
 | ||||
|  | @ -32,7 +32,7 @@ export class ColorPickerPopover extends React.Component<Props, State> { | |||
|     const { color, onChange, theme } = this.props; | ||||
| 
 | ||||
|     return activePicker === 'spectrum' ? ( | ||||
|       <SpectrumPicker color={color} onColorSelect={this.handleSpectrumColorSelect} options={{}} /> | ||||
|       <SpectrumPalette color={color} onColorSelect={this.handleSpectrumColorSelect} options={{}} /> | ||||
|     ) : ( | ||||
|       <NamedColorsPicker color={getColorName(color)} onChange={onChange} theme={theme} /> | ||||
|     ); | ||||
|  |  | |||
|  | @ -1,11 +1,12 @@ | |||
| import React, { FunctionComponent } from 'react'; | ||||
| import { find, upperFirst } from 'lodash'; | ||||
| import { Color, ColorsPalete, ColorDefinition, getColorForTheme } from '../../utils/colorsPalette'; | ||||
| import { Themeable } from '../../types'; | ||||
| import { ColorDefinition, getColorForTheme } from '../../utils/colorsPalette'; | ||||
| import { Color } from 'csstype'; | ||||
| import { find, upperFirst } from 'lodash'; | ||||
| 
 | ||||
| type ColorChangeHandler = (color: ColorDefinition) => void; | ||||
| 
 | ||||
| enum ColorSwatchVariant { | ||||
| export enum ColorSwatchVariant { | ||||
|   Small = 'small', | ||||
|   Large = 'large', | ||||
| } | ||||
|  | @ -50,14 +51,14 @@ const ColorSwatch: FunctionComponent<ColorSwatchProps> = ({ | |||
|   ); | ||||
| }; | ||||
| 
 | ||||
| interface ColorsGroupProps extends Themeable { | ||||
| interface NamedColorsGroupProps extends Themeable { | ||||
|   colors: ColorDefinition[]; | ||||
|   selectedColor?: Color; | ||||
|   onColorSelect: ColorChangeHandler; | ||||
|   key?: string; | ||||
| } | ||||
| 
 | ||||
| const ColorsGroup: FunctionComponent<ColorsGroupProps> = ({ | ||||
| const NamedColorsGroup: FunctionComponent<NamedColorsGroupProps> = ({ | ||||
|   colors, | ||||
|   selectedColor, | ||||
|   onColorSelect, | ||||
|  | @ -100,37 +101,4 @@ const ColorsGroup: FunctionComponent<ColorsGroupProps> = ({ | |||
|   ); | ||||
| }; | ||||
| 
 | ||||
| interface NamedColorsPickerProps extends Themeable { | ||||
|   color?: Color; | ||||
|   onChange: (colorName: string) => void; | ||||
| } | ||||
| 
 | ||||
| const NamedColorsPicker = ({ color, onChange, theme }: NamedColorsPickerProps) => { | ||||
|   const swatches: JSX.Element[] = []; | ||||
|   ColorsPalete.forEach((colors, hue) => { | ||||
|     swatches.push( | ||||
|       <ColorsGroup | ||||
|         key={hue} | ||||
|         theme={theme} | ||||
|         selectedColor={color} | ||||
|         colors={colors} | ||||
|         onColorSelect={color => onChange(color.name)} | ||||
|       /> | ||||
|     ); | ||||
|   }); | ||||
| 
 | ||||
|   return ( | ||||
|     <div | ||||
|       style={{ | ||||
|         display: 'grid', | ||||
|         gridTemplateColumns: 'repeat(3, 1fr)', | ||||
|         gridRowGap: '32px', | ||||
|         gridColumnGap: '32px', | ||||
|       }} | ||||
|     > | ||||
|       {swatches} | ||||
|     </div> | ||||
|   ); | ||||
| }; | ||||
| 
 | ||||
| export default NamedColorsPicker; | ||||
| export default NamedColorsGroup; | ||||
|  | @ -0,0 +1,42 @@ | |||
| import React from 'react'; | ||||
| import { Color, ColorsPalette } from '../../utils/colorsPalette'; | ||||
| import { Themeable } from '../../types/index'; | ||||
| import NamedColorsGroup from './NamedColorsGroup'; | ||||
| 
 | ||||
| interface NamedColorsPaletteProps extends Themeable { | ||||
|   color?: Color; | ||||
|   onChange: (colorName: string) => void; | ||||
| } | ||||
| 
 | ||||
| const NamedColorsPalette = ({ color, onChange, theme }: NamedColorsPaletteProps) => { | ||||
|   const swatches: JSX.Element[] = []; | ||||
| 
 | ||||
|   ColorsPalette.forEach((colors, hue) => { | ||||
|     swatches.push( | ||||
|       <NamedColorsGroup | ||||
|         key={hue} | ||||
|         theme={theme} | ||||
|         selectedColor={color} | ||||
|         colors={colors} | ||||
|         onColorSelect={color => { | ||||
|           onChange(color.name) | ||||
|         }} | ||||
|       /> | ||||
|     ); | ||||
|   }); | ||||
| 
 | ||||
|   return ( | ||||
|     <div | ||||
|       style={{ | ||||
|         display: 'grid', | ||||
|         gridTemplateColumns: 'repeat(3, 1fr)', | ||||
|         gridRowGap: '32px', | ||||
|         gridColumnGap: '32px', | ||||
|       }} | ||||
|     > | ||||
|       {swatches} | ||||
|     </div> | ||||
|   ); | ||||
| }; | ||||
| 
 | ||||
| export default NamedColorsPalette; | ||||
|  | @ -3,7 +3,7 @@ import * as PopperJS from 'popper.js'; | |||
| import { SeriesColorPickerPopover } from './SeriesColorPickerPopover'; | ||||
| import PopperController from '../Tooltip/PopperController'; | ||||
| import Popper from '../Tooltip/Popper'; | ||||
| import { Themeable } from '../../types'; | ||||
| import { Themeable, GrafanaTheme } from '../../types'; | ||||
| import { ColorPickerProps } from './ColorPicker'; | ||||
| 
 | ||||
| export interface SeriesColorPickerProps extends ColorPickerProps, Themeable { | ||||
|  | @ -37,7 +37,7 @@ export class SeriesColorPicker extends React.Component<SeriesColorPickerProps> { | |||
|   }; | ||||
| 
 | ||||
|   render() { | ||||
|     const { children } = this.props; | ||||
|     const { children, theme } = this.props; | ||||
|     return ( | ||||
|       <PopperController placement="bottom-start" content={this.renderPickerTabs()}> | ||||
|         {(showPopper, hidePopper, popperProps) => { | ||||
|  | @ -49,10 +49,21 @@ export class SeriesColorPicker extends React.Component<SeriesColorPickerProps> { | |||
|                   onMouseEnter={showPopper} | ||||
|                   onMouseLeave={hidePopper} | ||||
|                   referenceElement={this.pickerTriggerRef.current} | ||||
|                   className="ColorPicker" | ||||
|                   arrowClassName="popper__arrow" | ||||
|                   wrapperClassName="ColorPicker" | ||||
|                   renderArrow={({ arrowProps, placement }) => { | ||||
|                     return ( | ||||
|                       <div | ||||
|                         {...arrowProps} | ||||
|                         data-placement={placement} | ||||
|                         className={`ColorPicker__arrow ColorPicker__arrow--${ | ||||
|                           theme === GrafanaTheme.Light ? 'light' : 'dark' | ||||
|                         }`}
 | ||||
|                       /> | ||||
|                     ); | ||||
|                   }} | ||||
|                 /> | ||||
|               )} | ||||
| 
 | ||||
|               {React.cloneElement(children, { | ||||
|                 ref: this.pickerTriggerRef, | ||||
|                 onClick: showPopper, | ||||
|  |  | |||
|  | @ -9,7 +9,7 @@ export interface Props { | |||
|   onColorSelect: (color: string) => void; | ||||
| } | ||||
| 
 | ||||
| export class SpectrumPicker extends React.Component<Props, any> { | ||||
| export class SpectrumPalette extends React.Component<Props, any> { | ||||
|   elem: any; | ||||
|   isMoving: boolean; | ||||
| 
 | ||||
|  | @ -1,12 +1,107 @@ | |||
| $arrowSize: 10px; | ||||
| .ColorPicker { | ||||
|   .popper__arrow { | ||||
|     border-color: #f7f8fa; | ||||
|   } | ||||
|   @extend .popper; | ||||
| } | ||||
| 
 | ||||
| .ColorPicker__arrow { | ||||
|   width: 0; | ||||
|   height: 0; | ||||
|   border-style: solid; | ||||
|   position: absolute; | ||||
|   margin: 0px; | ||||
| 
 | ||||
|   &[data-placement^='top'] { | ||||
|     border-width: $arrowSize $arrowSize 0 $arrowSize; | ||||
|     border-left-color: transparent; | ||||
|     border-right-color: transparent; | ||||
|     border-bottom-color: transparent; | ||||
|     bottom: -$arrowSize; | ||||
|     left: calc(50% - $arrowSize); | ||||
|     padding-top: $arrowSize; | ||||
|   } | ||||
| 
 | ||||
|   &[data-placement^='bottom'] { | ||||
|     border-width: 0 $arrowSize $arrowSize $arrowSize; | ||||
|     border-left-color: transparent; | ||||
|     border-right-color: transparent; | ||||
|     border-top-color: transparent; | ||||
|     top: 0; | ||||
|     left: calc(50% - $arrowSize); | ||||
|   } | ||||
| 
 | ||||
|   &[data-placement^='bottom-start'] { | ||||
|     border-width: 0 $arrowSize $arrowSize $arrowSize; | ||||
|     border-left-color: transparent; | ||||
|     border-right-color: transparent; | ||||
|     border-top-color: transparent; | ||||
|     top: 0; | ||||
|     left: $arrowSize; | ||||
|   } | ||||
| 
 | ||||
|   &[data-placement^='bottom-end'] & { | ||||
|     border-width: 0 $arrowSize $arrowSize $arrowSize; | ||||
|     border-left-color: transparent; | ||||
|     border-right-color: transparent; | ||||
|     border-top-color: transparent; | ||||
|     top: 0; | ||||
|     left: calc(100% - $arrowSize); | ||||
|   } | ||||
| 
 | ||||
|   &[data-placement^='right'] { | ||||
|     border-width: $arrowSize $arrowSize $arrowSize 0; | ||||
|     border-left-color: transparent; | ||||
|     border-top-color: transparent; | ||||
|     border-bottom-color: transparent; | ||||
|     left: 0; | ||||
|     top: calc(50% - $arrowSize); | ||||
|   } | ||||
| 
 | ||||
|   &[data-placement^='left'] { | ||||
|     border-width: $arrowSize 0 $arrowSize $arrowSize; | ||||
|     border-top-color: transparent; | ||||
|     border-right-color: transparent; | ||||
|     border-bottom-color: transparent; | ||||
|     right: -$arrowSize; | ||||
|     top: calc(50% - $arrowSize); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| .ColorPicker__arrow--light { | ||||
|   border-color: #ffffff; | ||||
| } | ||||
| 
 | ||||
| .ColorPicker__arrow--dark { | ||||
|   border-color: #1e2028; | ||||
| } | ||||
| 
 | ||||
| // Top | ||||
| .ColorPicker[data-placement^='top'] { | ||||
|   padding-bottom: $arrowSize; | ||||
| } | ||||
| 
 | ||||
| // Bottom | ||||
| .ColorPicker[data-placement^='bottom'] { | ||||
|   padding-top: $arrowSize; | ||||
| } | ||||
| 
 | ||||
| .ColorPicker[data-placement^='bottom-start'] { | ||||
|   padding-top: $arrowSize; | ||||
| } | ||||
| 
 | ||||
| .ColorPicker[data-placement^='bottom-end'] { | ||||
|   padding-top: $arrowSize; | ||||
| } | ||||
| 
 | ||||
| // Right | ||||
| .ColorPicker[data-placement^='right'] { | ||||
|   padding-left: $arrowSize; | ||||
| } | ||||
| 
 | ||||
| // Left | ||||
| .ColorPicker[data-placement^='left'] { | ||||
|   padding-right: $arrowSize; | ||||
| } | ||||
| 
 | ||||
| .ColorPickerPopover { | ||||
|   border-radius: 3px; | ||||
| } | ||||
|  | @ -93,7 +188,7 @@ | |||
| } | ||||
| 
 | ||||
| .gf-color-picker__body { | ||||
|   padding-bottom: 10px; | ||||
|   padding-bottom: $arrowSize; | ||||
|   padding-left: 6px; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,6 +1,6 @@ | |||
| import React, { PureComponent } from 'react'; | ||||
| import * as PopperJS from 'popper.js'; | ||||
| import { Manager, Popper as ReactPopper } from 'react-popper'; | ||||
| import { Manager, Popper as ReactPopper, PopperArrowProps } from 'react-popper'; | ||||
| import { Portal } from '@grafana/ui'; | ||||
| import Transition from 'react-transition-group/Transition'; | ||||
| import { PopperContent } from './PopperController'; | ||||
|  | @ -22,12 +22,18 @@ interface Props extends React.HTMLAttributes<HTMLDivElement> { | |||
|   placement?: PopperJS.Placement; | ||||
|   content: PopperContent; | ||||
|   referenceElement: PopperJS.ReferenceObject; | ||||
|   arrowClassName?: string; | ||||
|   wrapperClassName?: string; | ||||
|   renderArrow?: ( | ||||
|     props: { | ||||
|       arrowProps: PopperArrowProps; | ||||
|       placement: string; | ||||
|     } | ||||
|   ) => JSX.Element; | ||||
| } | ||||
| 
 | ||||
| class Popper extends PureComponent<Props> { | ||||
|   render() { | ||||
|     const { show, placement, onMouseEnter, onMouseLeave, className, arrowClassName } = this.props; | ||||
|     const { show, placement, onMouseEnter, onMouseLeave, className, wrapperClassName, renderArrow } = this.props; | ||||
|     const { content } = this.props; | ||||
| 
 | ||||
|     return ( | ||||
|  | @ -53,16 +59,15 @@ class Popper extends PureComponent<Props> { | |||
|                         ...transitionStyles[transitionState], | ||||
|                       }} | ||||
|                       data-placement={placement} | ||||
|                       className={`popper`} | ||||
|                       className={`${wrapperClassName}`} | ||||
|                     > | ||||
|                       <div className={className}> | ||||
|                         {content} | ||||
|                         <div | ||||
|                           ref={arrowProps.ref} | ||||
|                           style={{ ...arrowProps.style }} | ||||
|                           data-placement={placement} | ||||
|                           className={arrowClassName} | ||||
|                         /> | ||||
|                         {renderArrow && | ||||
|                           renderArrow({ | ||||
|                             arrowProps, | ||||
|                             placement, | ||||
|                           })} | ||||
|                       </div> | ||||
|                     </div> | ||||
|                   ); | ||||
|  |  | |||
|  | @ -27,8 +27,11 @@ export const Tooltip = ({ children, theme, ...controllerProps }: TooltipProps) = | |||
|                 onMouseEnter={showPopper} | ||||
|                 onMouseLeave={hidePopper} | ||||
|                 referenceElement={tooltipTriggerRef.current} | ||||
|                 wrapperClassName='popper' | ||||
|                 className={popperBackgroundClassName} | ||||
|                 arrowClassName={'popper__arrow'} | ||||
|                 renderArrow={({ arrowProps, placement }) => ( | ||||
|                   <div className="popper__arrow" data-placement={placement} {...arrowProps} /> | ||||
|                 )} | ||||
|               /> | ||||
|             )} | ||||
|             {React.cloneElement(children, { | ||||
|  |  | |||
|  | @ -44,7 +44,6 @@ $popper-margin-from-ref: 5px; | |||
|   margin: 0px; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| // Top | ||||
| .popper[data-placement^='top'] { | ||||
|   padding-bottom: $popper-margin-from-ref; | ||||
|  |  | |||
|  | @ -1,11 +1,7 @@ | |||
| import { getColorName, getColorDefinition, ColorsPalete, buildColorDefinition } from './colorsPalette'; | ||||
| import { getColorName, getColorDefinition, getColorByName, SemiDarkBlue, getColorFromHexRgbOrName } from './colorsPalette'; | ||||
| import { GrafanaTheme } from '../types'; | ||||
| 
 | ||||
| describe('colors', () => { | ||||
|   const FakeBlue = buildColorDefinition('blue', 'blue', ['#0000ff', '#00000ee']); | ||||
| 
 | ||||
|   beforeAll(() => { | ||||
|     ColorsPalete.set('blue', [FakeBlue]); | ||||
|   }); | ||||
| 
 | ||||
|   describe('getColorDefinition', () => { | ||||
|     it('returns undefined for unknown hex', () => { | ||||
|  | @ -13,8 +9,8 @@ describe('colors', () => { | |||
|     }); | ||||
| 
 | ||||
|     it('returns definition for known hex', () => { | ||||
|       expect(getColorDefinition(FakeBlue.variants.light)).toEqual(FakeBlue); | ||||
|       expect(getColorDefinition(FakeBlue.variants.dark)).toEqual(FakeBlue); | ||||
|       expect(getColorDefinition(SemiDarkBlue.variants.light)).toEqual(SemiDarkBlue); | ||||
|       expect(getColorDefinition(SemiDarkBlue.variants.dark)).toEqual(SemiDarkBlue); | ||||
|     }); | ||||
|   }); | ||||
| 
 | ||||
|  | @ -24,8 +20,39 @@ describe('colors', () => { | |||
|     }); | ||||
| 
 | ||||
|     it('returns name for known hex', () => { | ||||
|       expect(getColorName(FakeBlue.variants.light)).toEqual(FakeBlue.name); | ||||
|       expect(getColorName(FakeBlue.variants.dark)).toEqual(FakeBlue.name); | ||||
|       expect(getColorName(SemiDarkBlue.variants.light)).toEqual(SemiDarkBlue.name); | ||||
|       expect(getColorName(SemiDarkBlue.variants.dark)).toEqual(SemiDarkBlue.name); | ||||
|     }); | ||||
|   }); | ||||
| 
 | ||||
|   describe('getColorByName', () => { | ||||
|     it('returns undefined for unknown color', () => { | ||||
|       expect(getColorByName('aruba-sunshine')).toBeUndefined(); | ||||
|     }); | ||||
| 
 | ||||
|     it('returns color definiton for known color', () => { | ||||
|       expect(getColorByName(SemiDarkBlue.name)).toBe(SemiDarkBlue); | ||||
|     }); | ||||
| 
 | ||||
|   }); | ||||
|   describe('getColorFromHexRgbOrName', () => { | ||||
|     it('returns undefined for unknown color', () => { | ||||
|       expect(() => getColorFromHexRgbOrName('aruba-sunshine')).toThrow(); | ||||
|     }); | ||||
| 
 | ||||
|     it('returns dark hex variant for known color if theme not specified', () => { | ||||
|       expect(getColorFromHexRgbOrName(SemiDarkBlue.name)).toBe(SemiDarkBlue.variants.dark); | ||||
|     }); | ||||
| 
 | ||||
|     it('returns correct variant\'s hex for known color if theme specified', () => { | ||||
|       expect(getColorFromHexRgbOrName(SemiDarkBlue.name, GrafanaTheme.Light)).toBe(SemiDarkBlue.variants.light); | ||||
|     }); | ||||
| 
 | ||||
|     it('returns color if specified as hex or rgb/a', () => { | ||||
|       expect(getColorFromHexRgbOrName('ff0000')).toBe('ff0000'); | ||||
|       expect(getColorFromHexRgbOrName('#ff0000')).toBe('#ff0000'); | ||||
|       expect(getColorFromHexRgbOrName('rgb(0,0,0)')).toBe('rgb(0,0,0)'); | ||||
|       expect(getColorFromHexRgbOrName('rgba(0,0,0,1)')).toBe('rgba(0,0,0,1)'); | ||||
|     }); | ||||
|   }); | ||||
| }); | ||||
|  |  | |||
|  | @ -47,7 +47,7 @@ export type ColorDefinition = { | |||
|   variants: ThemeVariants; | ||||
| }; | ||||
| 
 | ||||
| export const ColorsPalete = new Map<Hue, ColorDefinition[]>(); | ||||
| export const ColorsPalette = new Map<Hue, ColorDefinition[]>(); | ||||
| 
 | ||||
| export const buildColorDefinition = ( | ||||
|   hue: Hue, | ||||
|  | @ -107,15 +107,15 @@ const blues = [BasicBlue, DarkBlue, SemiDarkBlue, LightBlue, SuperLightBlue]; | |||
| const oranges = [BasicOrange, DarkOrange, SemiDarkOrange, LightOrange, SuperLightOrange]; | ||||
| const purples = [BasicPurple, DarkPurple, SemiDarkPurple, LightPurple, SuperLightPurple]; | ||||
| 
 | ||||
| ColorsPalete.set('green', greens); | ||||
| ColorsPalete.set('yellow', yellows); | ||||
| ColorsPalete.set('red', reds); | ||||
| ColorsPalete.set('blue', blues); | ||||
| ColorsPalete.set('orange', oranges); | ||||
| ColorsPalete.set('purple', purples); | ||||
| ColorsPalette.set('green', greens); | ||||
| ColorsPalette.set('yellow', yellows); | ||||
| ColorsPalette.set('red', reds); | ||||
| ColorsPalette.set('blue', blues); | ||||
| ColorsPalette.set('orange', oranges); | ||||
| ColorsPalette.set('purple', purples); | ||||
| 
 | ||||
| export const getColorDefinition = (hex: string): ColorDefinition | undefined => { | ||||
|   return flatten(Array.from(ColorsPalete.values())).filter(definition => | ||||
|   return flatten(Array.from(ColorsPalette.values())).filter(definition => | ||||
|     some(values(definition.variants), color => color === hex) | ||||
|   )[0]; | ||||
| }; | ||||
|  | @ -137,6 +137,25 @@ export const getColorName = (color: string): Color | undefined => { | |||
|   return color as Color; | ||||
| }; | ||||
| 
 | ||||
| export const getColorByName = (colorName: string) => { | ||||
|   const definition = flatten(Array.from(ColorsPalette.values())).filter(definition => definition.name === colorName); | ||||
|   return definition.length > 0 ? definition[0] : undefined; | ||||
| }; | ||||
| 
 | ||||
| export const getColorFromHexRgbOrName = (color: string, theme?: GrafanaTheme): string => { | ||||
|   if (color.indexOf('rgb') > -1 || isHex(color)) { | ||||
|     return color; | ||||
|   } | ||||
| 
 | ||||
|   const colorDefinition = getColorByName(color); | ||||
| 
 | ||||
|   if (!colorDefinition) { | ||||
|     throw new Error('Unknown color'); | ||||
|   } | ||||
| 
 | ||||
|   return theme ? colorDefinition.variants[theme] : colorDefinition.variants.dark; | ||||
| }; | ||||
| 
 | ||||
| export const getColorForTheme = (color: ColorDefinition, theme?: GrafanaTheme) => { | ||||
|   return theme ? color.variants[theme] : color.variants.dark; | ||||
| }; | ||||
|  |  | |||
|  | @ -1,7 +1,6 @@ | |||
| import kbn from 'app/core/utils/kbn'; | ||||
| import { getFlotTickDecimals } from 'app/core/utils/ticks'; | ||||
| import _ from 'lodash'; | ||||
| import { ColorDefinition } from '@grafana/ui/src/utils/colorsPalette'; | ||||
| 
 | ||||
| function matchSeriesOverride(aliasOrRegex, seriesAlias) { | ||||
|   if (!aliasOrRegex) { | ||||
|  | @ -357,13 +356,8 @@ export default class TimeSeries { | |||
|     return false; | ||||
|   } | ||||
| 
 | ||||
|   setColor(color: string | ColorDefinition) { | ||||
|     if (typeof color === 'string') { | ||||
|   setColor(color: string) { | ||||
|     this.color = color; | ||||
|     this.bars.fillColor = color; | ||||
|     } else { | ||||
|       this.color = color.variants.dark; | ||||
|       this.bars.fillColor = color.variants.dark; | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  |  | |||
|  | @ -1,7 +1,9 @@ | |||
| import _ from 'lodash'; | ||||
| import { colors } from '@grafana/ui'; | ||||
| import { colors, GrafanaTheme } from '@grafana/ui'; | ||||
| 
 | ||||
| import TimeSeries from 'app/core/time_series2'; | ||||
| import { getColorFromHexRgbOrName } from '@grafana/ui/src/utils/colorsPalette'; | ||||
| import config from 'app/core/config'; | ||||
| 
 | ||||
| export class DataProcessor { | ||||
|   constructor(private panel) {} | ||||
|  | @ -107,12 +109,13 @@ export class DataProcessor { | |||
|     const alias = seriesData.target; | ||||
| 
 | ||||
|     const colorIndex = index % colors.length; | ||||
| 
 | ||||
|     const color = this.panel.aliasColors[alias] || colors[colorIndex]; | ||||
| 
 | ||||
|     const series = new TimeSeries({ | ||||
|       datapoints: datapoints, | ||||
|       alias: alias, | ||||
|       color: color, | ||||
|       color: getColorFromHexRgbOrName(color, config.bootData.user.lightTheme ? GrafanaTheme.Light : GrafanaTheme.Dark), | ||||
|       unit: seriesData.unit, | ||||
|     }); | ||||
| 
 | ||||
|  |  | |||
|  | @ -9,6 +9,9 @@ import _ from 'lodash'; | |||
| import { MetricsPanelCtrl } from 'app/plugins/sdk'; | ||||
| import { DataProcessor } from './data_processor'; | ||||
| import { axesEditorComponent } from './axes_editor'; | ||||
| import { getColorFromHexRgbOrName } from '@grafana/ui/src/utils/colorsPalette'; | ||||
| import config from 'app/core/config'; | ||||
| import { GrafanaTheme } from '@grafana/ui'; | ||||
| 
 | ||||
| class GraphCtrl extends MetricsPanelCtrl { | ||||
|   static template = template; | ||||
|  | @ -242,8 +245,8 @@ class GraphCtrl extends MetricsPanelCtrl { | |||
|   } | ||||
| 
 | ||||
|   onColorChange = (series, color) => { | ||||
|     series.setColor(color); | ||||
|     this.panel.aliasColors[series.alias] = series.color; | ||||
|     series.setColor(getColorFromHexRgbOrName(color, config.bootData.user.lightTheme ? GrafanaTheme.Light : GrafanaTheme.Dark)); | ||||
|     this.panel.aliasColors[series.alias] = color; | ||||
|     this.render(); | ||||
|   }; | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue