textBox.tsx 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. import { css } from '@emotion/css';
  2. import React, { PureComponent } from 'react';
  3. import { GrafanaTheme2 } from '@grafana/data';
  4. import { stylesFactory } from '@grafana/ui';
  5. import { config } from 'app/core/config';
  6. import { DimensionContext } from 'app/features/dimensions/context';
  7. import { ColorDimensionEditor } from 'app/features/dimensions/editors/ColorDimensionEditor';
  8. import { TextDimensionEditor } from 'app/features/dimensions/editors/TextDimensionEditor';
  9. import { ColorDimensionConfig, TextDimensionConfig } from 'app/features/dimensions/types';
  10. import { CanvasElementItem, CanvasElementProps } from '../element';
  11. export enum Align {
  12. Left = 'left',
  13. Center = 'center',
  14. Right = 'right',
  15. }
  16. export enum VAlign {
  17. Top = 'top',
  18. Middle = 'middle',
  19. Bottom = 'bottom',
  20. }
  21. interface TextBoxData {
  22. text?: string;
  23. color?: string;
  24. size?: number; // 0 or missing will "auto size"
  25. align: Align;
  26. valign: VAlign;
  27. }
  28. interface TextBoxConfig {
  29. text?: TextDimensionConfig;
  30. color?: ColorDimensionConfig;
  31. size?: number; // 0 or missing will "auto size"
  32. align: Align;
  33. valign: VAlign;
  34. }
  35. class TextBoxDisplay extends PureComponent<CanvasElementProps<TextBoxConfig, TextBoxData>> {
  36. render() {
  37. const { data } = this.props;
  38. const styles = getStyles(config.theme2, data);
  39. return (
  40. <div className={styles.container}>
  41. <span className={styles.span}>{data?.text}</span>
  42. </div>
  43. );
  44. }
  45. }
  46. const getStyles = stylesFactory((theme: GrafanaTheme2, data) => ({
  47. container: css`
  48. position: absolute;
  49. height: 100%;
  50. width: 100%;
  51. display: table;
  52. `,
  53. span: css`
  54. display: table-cell;
  55. vertical-align: ${data.valign};
  56. text-align: ${data.align};
  57. font-size: ${data?.size}px;
  58. color: ${data?.color};
  59. `,
  60. }));
  61. export const textBoxItem: CanvasElementItem<TextBoxConfig, TextBoxData> = {
  62. id: 'text-box',
  63. name: 'Text',
  64. description: 'Text box',
  65. display: TextBoxDisplay,
  66. defaultSize: {
  67. width: 240,
  68. height: 160,
  69. },
  70. getNewOptions: (options) => ({
  71. background: {
  72. color: {
  73. fixed: 'grey',
  74. },
  75. },
  76. ...options,
  77. config: {
  78. align: Align.Left,
  79. valign: VAlign.Middle,
  80. },
  81. }),
  82. // Called when data changes
  83. prepareData: (ctx: DimensionContext, cfg: TextBoxConfig) => {
  84. const data: TextBoxData = {
  85. text: cfg.text ? ctx.getText(cfg.text).value() : '',
  86. align: cfg.align ?? Align.Center,
  87. valign: cfg.valign ?? VAlign.Middle,
  88. size: cfg.size,
  89. };
  90. if (cfg.color) {
  91. data.color = ctx.getColor(cfg.color).value();
  92. }
  93. return data;
  94. },
  95. // Heatmap overlay options
  96. registerOptionsUI: (builder) => {
  97. const category = ['Text box'];
  98. builder
  99. .addCustomEditor({
  100. category,
  101. id: 'textSelector',
  102. path: 'config.text',
  103. name: 'Text',
  104. editor: TextDimensionEditor,
  105. })
  106. .addCustomEditor({
  107. category,
  108. id: 'config.color',
  109. path: 'config.color',
  110. name: 'Text color',
  111. editor: ColorDimensionEditor,
  112. settings: {},
  113. defaultValue: {},
  114. })
  115. .addRadio({
  116. category,
  117. path: 'config.align',
  118. name: 'Align text',
  119. settings: {
  120. options: [
  121. { value: Align.Left, label: 'Left' },
  122. { value: Align.Center, label: 'Center' },
  123. { value: Align.Right, label: 'Right' },
  124. ],
  125. },
  126. defaultValue: Align.Left,
  127. })
  128. .addRadio({
  129. category,
  130. path: 'config.valign',
  131. name: 'Vertical align',
  132. settings: {
  133. options: [
  134. { value: VAlign.Top, label: 'Top' },
  135. { value: VAlign.Middle, label: 'Middle' },
  136. { value: VAlign.Bottom, label: 'Bottom' },
  137. ],
  138. },
  139. defaultValue: VAlign.Middle,
  140. })
  141. .addNumberInput({
  142. category,
  143. path: 'config.size',
  144. name: 'Text size',
  145. settings: {
  146. placeholder: 'Auto',
  147. },
  148. });
  149. },
  150. };