import { css } from '@emotion/css'; import React from 'react'; import { GrafanaTheme2 } from '@grafana/data'; import { ScalarDimensionConfig } from '@grafana/schema'; import { useStyles2 } from '@grafana/ui'; import { DimensionContext } from 'app/features/dimensions'; import { ScalarDimensionEditor } from 'app/features/dimensions/editors'; import { CanvasElementItem, CanvasElementProps, defaultBgColor } 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 = ({ data }: CanvasElementProps) => { const styles = useStyles2(getStyles); 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, background: { color: { fixed: 'transparent', }, }, }), // 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({ transformOrigin: '50% 50%', transformBox: 'fill-box', display: 'block', '@keyframes spin': { from: { transform: 'rotate(0deg)', }, to: { transform: 'rotate(360deg)', }, }, }), propellerCW: css({ animationDirection: 'normal', }), propellerCCW: css({ animationDirection: 'reverse', }), });