import { css } from '@emotion/css'; import React, { FC } from 'react'; import { GrafanaTheme2 } from '@grafana/data'; import { useStyles2 } from '@grafana/ui'; import { DimensionContext, ScalarDimensionConfig } from 'app/features/dimensions'; import { ScalarDimensionEditor } from 'app/features/dimensions/editors'; import { CanvasElementItem, CanvasElementProps } from '../element'; interface DroneTopData { bRightRotorRPM?: number; bLeftRotorRPM?: number; fRightRotorRPM?: number; fLeftRotorRPM?: number; yawAngle?: number; } interface DroneTopConfig { bRightRotorRPM?: ScalarDimensionConfig; bLeftRotorRPM?: ScalarDimensionConfig; fRightRotorRPM?: ScalarDimensionConfig; fLeftRotorRPM?: ScalarDimensionConfig; yawAngle?: ScalarDimensionConfig; } const DroneTopDisplay: FC> = (props) => { const styles = useStyles2(getStyles); const { data } = props; const fRightRotorAnimation = `spin ${data?.fRightRotorRPM ? 60 / Math.abs(data.fRightRotorRPM) : 0}s linear infinite`; const fLeftRotorAnimation = `spin ${data?.fLeftRotorRPM ? 60 / Math.abs(data.fLeftRotorRPM) : 0}s linear infinite`; const bRightRotorAnimation = `spin ${data?.bRightRotorRPM ? 60 / Math.abs(data.bRightRotorRPM) : 0}s linear infinite`; const bLeftRotorAnimation = `spin ${data?.bLeftRotorRPM ? 60 / Math.abs(data.bLeftRotorRPM) : 0}s linear infinite`; const droneTopTransformStyle = `rotate(${data?.yawAngle ? data.yawAngle : 0}deg)`; return ( ); }; export const droneTopItem: CanvasElementItem = { id: 'droneTop', name: 'Drone Top', description: 'Drone top', display: DroneTopDisplay, defaultSize: { width: 100, height: 100, }, getNewOptions: (options) => ({ ...options, }), // Called when data changes prepareData: (ctx: DimensionContext, cfg: DroneTopConfig) => { const data: DroneTopData = { bRightRotorRPM: cfg?.bRightRotorRPM ? ctx.getScalar(cfg.bRightRotorRPM).value() : 0, bLeftRotorRPM: cfg?.bLeftRotorRPM ? ctx.getScalar(cfg.bLeftRotorRPM).value() : 0, fRightRotorRPM: cfg?.fRightRotorRPM ? ctx.getScalar(cfg.fRightRotorRPM).value() : 0, fLeftRotorRPM: cfg?.fLeftRotorRPM ? ctx.getScalar(cfg.fLeftRotorRPM).value() : 0, yawAngle: cfg?.yawAngle ? ctx.getScalar(cfg.yawAngle).value() : 0, }; return data; }, registerOptionsUI: (builder) => { const category = ['Drone Top']; builder .addCustomEditor({ category, id: 'yawAngle', path: 'config.yawAngle', name: 'Yaw Angle', editor: ScalarDimensionEditor, }) .addCustomEditor({ category, id: 'fRightRotorRPM', path: 'config.fRightRotorRPM', name: 'Front Right Rotor RPM', editor: ScalarDimensionEditor, }) .addCustomEditor({ category, id: 'fLeftRotorRPM', path: 'config.fLeftRotorRPM', name: 'Front Left Rotor RPM', editor: ScalarDimensionEditor, }) .addCustomEditor({ category, id: 'bRightRotorRPM', path: 'config.bRightRotorRPM', name: 'Back Right Rotor RPM', editor: ScalarDimensionEditor, }) .addCustomEditor({ category, id: 'bLeftRotorRPM', path: 'config.bLeftRotorRPM', name: 'Back Left Rotor RPM', editor: ScalarDimensionEditor, }); }, }; const getStyles = (theme: GrafanaTheme2) => ({ propeller: css` transform-origin: 50% 50%; transform-box: fill-box; display: block; @keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } } `, propellerCW: css` animation-direction: normal; `, propellerCCW: css` animation-direction: reverse; `, });