droneSide.tsx 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. import { css } from '@emotion/css';
  2. import React, { FC } from 'react';
  3. import { GrafanaTheme2 } from '@grafana/data';
  4. import { useStyles2 } from '@grafana/ui';
  5. import { DimensionContext, ScalarDimensionConfig } from 'app/features/dimensions';
  6. import { ScalarDimensionEditor } from 'app/features/dimensions/editors';
  7. import { CanvasElementItem, CanvasElementProps } from '../element';
  8. interface DroneSideData {
  9. pitchAngle?: number;
  10. }
  11. interface DroneSideConfig {
  12. pitchAngle?: ScalarDimensionConfig;
  13. }
  14. const DroneSideDisplay: FC<CanvasElementProps<DroneSideConfig, DroneSideData>> = (props) => {
  15. const styles = useStyles2(getStyles);
  16. const { data } = props;
  17. const droneSidePitchTransformStyle = `rotate(${data?.pitchAngle ? data.pitchAngle : 0}deg)`;
  18. return (
  19. <svg
  20. className={styles.droneSide}
  21. xmlns="http://www.w3.org/2000/svg"
  22. xmlnsXlink="http://www.w3.org/1999/xlink"
  23. viewBox="0 0 1300 290"
  24. style={{ transform: droneSidePitchTransformStyle }}
  25. >
  26. <g className="arms" stroke="black" strokeWidth="28px">
  27. <line x1="510" x2="320" y1="100" y2="150" />
  28. <line x1="510" x2="320" y1="190" y2="210" />
  29. <line x1="790" x2="980" y1="190" y2="210" />
  30. <line x1="790" x2="980" y1="100" y2="150" />
  31. </g>
  32. <g className="body" stroke="black" strokeWidth="28px">
  33. <path
  34. fill="none"
  35. d=" M 510 130 C 510 124 510 110 510 100 C 510 90 530 71 540 70 C 640 61 670 60 760 70 C 770 71 790 90 790 100 Q 790 120 790 130 L 790 130 Q 790 177 790 196 C 790 207 770 225 760 226 C 670 236 640 236 540 226 C 530 226 510 206 510 196 Q 510 177 510 130 Q 510 133 510 130 Z "
  36. />
  37. </g>
  38. <g className="motors" stroke="black" strokeWidth="28px">
  39. <path
  40. className="motor"
  41. fill="none"
  42. d=" M 320 60 L 250 60 L 250 230 L 260 290 L 310 290 L 320 230 L 320 60 Z "
  43. />
  44. <path
  45. className="motor"
  46. fill="none"
  47. d=" M 1050 60 L 980 60 L 980 230 L 990 290 L 1040 290 L 1050 230 L 1050 60 Z "
  48. />
  49. </g>
  50. <g className="propellers" fill="black">
  51. <path
  52. className="prop"
  53. d=" M 270 60 L 300 60 L 300 20 Q 311 30 330 30 Q 349 30 570 10 L 300 10 Q 300 0 290 0 C 286 0 284 0 280 0 Q 270 0 270 10 L 0 10 Q 220 30 240 30 Q 260 30 270 20 L 270 60 Z "
  54. />
  55. <path
  56. className="prop"
  57. d=" M 1000 60 L 1030 60 L 1030 20 Q 1041 30 1060 30 Q 1079 30 1300 10 L 1030 10 Q 1030 0 1020 0 C 1016 0 1014 0 1010 0 Q 1000 0 1000 10 L 730 10 Q 950 30 970 30 Q 990 30 1000 20 L 1000 60 Z "
  58. />
  59. </g>
  60. </svg>
  61. );
  62. };
  63. export const droneSideItem: CanvasElementItem<any, any> = {
  64. id: 'droneSide',
  65. name: 'Drone Side',
  66. description: 'Drone Side',
  67. display: DroneSideDisplay,
  68. defaultSize: {
  69. width: 100,
  70. height: 100,
  71. },
  72. getNewOptions: (options) => ({
  73. ...options,
  74. }),
  75. // Called when data changes
  76. prepareData: (ctx: DimensionContext, cfg: DroneSideConfig) => {
  77. const data: DroneSideData = {
  78. pitchAngle: cfg?.pitchAngle ? ctx.getScalar(cfg.pitchAngle).value() : 0,
  79. };
  80. return data;
  81. },
  82. registerOptionsUI: (builder) => {
  83. const category = ['Drone Side'];
  84. builder.addCustomEditor({
  85. category,
  86. id: 'pitchAngle',
  87. path: 'config.pitchAngle',
  88. name: 'Pitch Angle',
  89. editor: ScalarDimensionEditor,
  90. });
  91. },
  92. };
  93. const getStyles = (theme: GrafanaTheme2) => ({
  94. droneSide: css`
  95. transition: transform 0.4s;
  96. `,
  97. });