@luxonis/visualizer-protobuf 2.26.0 → 2.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/dist/{index-Zijk5SvX.js → index-B1pNpslP.js} +1 -1
  2. package/dist/{index-CkN9fMlH.js → index-B4d7dS8a.js} +1 -1
  3. package/dist/{index-CP4Zviq2.js → index-B5_Aa-W3.js} +1 -1
  4. package/dist/{index-BTdZSETz.js → index-BNXdmaeO.js} +1 -1
  5. package/dist/{index-DMzCNF_e.js → index-BZ8z044k.js} +1 -1
  6. package/dist/{index-CPTbtbj3.js → index-BuRQ7ljn.js} +133 -105
  7. package/dist/{index-cLRC4uIT.js → index-CGXxFWjz.js} +1 -1
  8. package/dist/{index-DcFvTNvR.js → index-CIHmVsn2.js} +1 -1
  9. package/dist/{index-NiMrvEhw.js → index-CJSOG1CX.js} +2 -2
  10. package/dist/{index-BQnK1LTP.js → index-CLPc3bUH.js} +1 -1
  11. package/dist/{index-DFHs4aUN.js → index-CXdNn-IZ.js} +1 -1
  12. package/dist/{index-Cia95HmM.js → index-CdXrBVPC.js} +177 -36
  13. package/dist/{index-CqMDGXcF.js → index-DE0_tKGA.js} +1 -1
  14. package/dist/{index-ttl4cqP0.js → index-DZgY6A3h.js} +1 -1
  15. package/dist/{index-B2-O30qH.js → index-DbT8vr6l.js} +1 -1
  16. package/dist/{index-DLRgXO8y.js → index-DsO3GPWF.js} +1 -1
  17. package/dist/{index-i-2ofHyT.js → index-I0XgHBlj.js} +1 -1
  18. package/dist/{index-BGrTBljs.js → index-LmBY2nOo.js} +1 -1
  19. package/dist/{index-AHg_yzKN.js → index-pwNtzQuf.js} +1 -1
  20. package/dist/index.js +1 -1
  21. package/dist/lib/src/components/Panel.d.ts +2 -1
  22. package/dist/lib/src/components/Panel.d.ts.map +1 -1
  23. package/dist/lib/src/components/Panel.js +8 -8
  24. package/dist/lib/src/components/Panel.js.map +1 -1
  25. package/dist/lib/src/components/PanelToolbar.d.ts +1 -0
  26. package/dist/lib/src/components/PanelToolbar.d.ts.map +1 -1
  27. package/dist/lib/src/components/PanelToolbar.js +9 -4
  28. package/dist/lib/src/components/PanelToolbar.js.map +1 -1
  29. package/dist/lib/src/index.d.ts +1 -0
  30. package/dist/lib/src/index.d.ts.map +1 -1
  31. package/dist/lib/src/index.js +1 -0
  32. package/dist/lib/src/index.js.map +1 -1
  33. package/dist/lib/src/messaging/deserialization/pointcloud/poitcloudPoolManager.d.ts.map +1 -1
  34. package/dist/lib/src/messaging/deserialization/pointcloud/poitcloudPoolManager.js +19 -8
  35. package/dist/lib/src/messaging/deserialization/pointcloud/poitcloudPoolManager.js.map +1 -1
  36. package/dist/lib/src/panels/ImagePanel.d.ts +1 -0
  37. package/dist/lib/src/panels/ImagePanel.d.ts.map +1 -1
  38. package/dist/lib/src/panels/ImagePanel.js +7 -3
  39. package/dist/lib/src/panels/ImagePanel.js.map +1 -1
  40. package/dist/lib/src/panels/PointCloudPanel.js +1 -1
  41. package/dist/lib/src/utils/metrics-manager.d.ts.map +1 -1
  42. package/dist/lib/src/utils/metrics-manager.js +6 -2
  43. package/dist/lib/src/utils/metrics-manager.js.map +1 -1
  44. package/dist/packages/studio-base/src/panels/ThreeDeeRender/IRenderer.d.ts +2 -0
  45. package/dist/packages/studio-base/src/panels/ThreeDeeRender/IRenderer.d.ts.map +1 -1
  46. package/dist/packages/studio-base/src/panels/ThreeDeeRender/IRenderer.js.map +1 -1
  47. package/dist/packages/studio-base/src/panels/ThreeDeeRender/Renderer.d.ts +1 -0
  48. package/dist/packages/studio-base/src/panels/ThreeDeeRender/Renderer.d.ts.map +1 -1
  49. package/dist/packages/studio-base/src/panels/ThreeDeeRender/Renderer.js +3 -0
  50. package/dist/packages/studio-base/src/panels/ThreeDeeRender/Renderer.js.map +1 -1
  51. package/dist/packages/studio-base/src/panels/ThreeDeeRender/ThreeDeeRender.d.ts +1 -0
  52. package/dist/packages/studio-base/src/panels/ThreeDeeRender/ThreeDeeRender.d.ts.map +1 -1
  53. package/dist/packages/studio-base/src/panels/ThreeDeeRender/ThreeDeeRender.js +4 -3
  54. package/dist/packages/studio-base/src/panels/ThreeDeeRender/ThreeDeeRender.js.map +1 -1
  55. package/dist/packages/studio-base/src/panels/ThreeDeeRender/index.d.ts +1 -0
  56. package/dist/packages/studio-base/src/panels/ThreeDeeRender/index.d.ts.map +1 -1
  57. package/dist/packages/studio-base/src/panels/ThreeDeeRender/index.js +5 -3
  58. package/dist/packages/studio-base/src/panels/ThreeDeeRender/index.js.map +1 -1
  59. package/dist/packages/studio-base/src/panels/ThreeDeeRender/renderables/CameraStateSettings.d.ts.map +1 -1
  60. package/dist/packages/studio-base/src/panels/ThreeDeeRender/renderables/CameraStateSettings.js +2 -1
  61. package/dist/packages/studio-base/src/panels/ThreeDeeRender/renderables/CameraStateSettings.js.map +1 -1
  62. package/dist/packages/studio-base/src/panels/ThreeDeeRender/renderables/ImageMode/ImageMode.d.ts +1 -0
  63. package/dist/packages/studio-base/src/panels/ThreeDeeRender/renderables/ImageMode/ImageMode.d.ts.map +1 -1
  64. package/dist/packages/studio-base/src/panels/ThreeDeeRender/renderables/ImageMode/ImageMode.js +4 -0
  65. package/dist/packages/studio-base/src/panels/ThreeDeeRender/renderables/ImageMode/ImageMode.js.map +1 -1
  66. package/dist/packages/studio-base/src/panels/ThreeDeeRender/renderables/ImageMode/MessageHandler.d.ts +6 -2
  67. package/dist/packages/studio-base/src/panels/ThreeDeeRender/renderables/ImageMode/MessageHandler.d.ts.map +1 -1
  68. package/dist/packages/studio-base/src/panels/ThreeDeeRender/renderables/ImageMode/MessageHandler.js +141 -25
  69. package/dist/packages/studio-base/src/panels/ThreeDeeRender/renderables/ImageMode/MessageHandler.js.map +1 -1
  70. package/package.json +1 -1
@@ -3,7 +3,7 @@ import React__default, { useReducer, useRef, useCallback, useLayoutEffect, Compo
3
3
  import ReactDOM__default from 'react-dom';
4
4
  import { S as isSymbol, U as toString, V as keys, W as getSymbols$1, X as stubArray, Y as arrayPush, Z as baseGetAllKeys, g as getTag, $ as getAllKeys, k as baseGet, c as baseIteratee, j as castPath, t as toKey, a0 as arrayMap$1, a1 as baseUniq, b as baseFlatten, a2 as useMustNotChange, a3 as useCurrentLayoutActions, a4 as useCurrentLayoutSelector, r as reportError, A as AppError, L as Logger, u as useGuaranteedContext, a5 as usePanelMosaicId, a6 as useSelectedPanels, a7 as PANEL_TITLE_CONFIG_KEY, a8 as noop$4, o as getPanelTypeFromId, M as useShallowMemo, T as TAB_PANEL_TYPE, J as filterMap, d as dist$3, a9 as useAppConfiguration, aa as useValueChangedDebugLog, ab as useJsonTreeTheme } from './tslib.es6-C73eoP_E.js';
5
5
  import { createStore, useStore } from 'zustand';
6
- import { g as generateUtilityClass, c as createAggregator, f as flatRest, b as baseSet, A as AnalyticsContext, P as PropTypes, E as ErrorDisplay, S as Stack$1, m as makeStyles$1, _ as _extends$1, W as WorkspaceContext, u as useAnalytics, a as AppEvent, L as LeftSidebarItemKeys, R as RightSidebarItemKeys, d as useTranslation, e as usePanelCatalog, h as EmptyState, i as isEmpty, j as PanelContext, k as PanelCatalogContext, l as usePanelStateStore, n as useDefaultPanelTitle, o as useWorkspaceStore, p as WorkspaceStoreSelectors, q as difference, r as usePanelContext, s as useMessagePipeline, v as v4, t as useHoverValue, w as useSetHoverValue, x as useClearHoverValue, y as useMessagePipelineGetter, z as usePanelSettingsTreeUpdate, B as PlayerCapabilities, C as assertNever, D as PlayerPresence, F as isEqual, G as isDesktopApp, H as createTheme, I as propTypesExports } from './index-CPTbtbj3.js';
6
+ import { g as generateUtilityClass, c as createAggregator, f as flatRest, b as baseSet, A as AnalyticsContext, P as PropTypes, E as ErrorDisplay, S as Stack$1, m as makeStyles$1, _ as _extends$1, W as WorkspaceContext, u as useAnalytics, a as AppEvent, L as LeftSidebarItemKeys, R as RightSidebarItemKeys, d as useTranslation, e as usePanelCatalog, h as EmptyState, i as isEmpty, j as PanelContext, k as PanelCatalogContext, l as usePanelStateStore, n as useDefaultPanelTitle, o as useWorkspaceStore, p as WorkspaceStoreSelectors, q as difference, r as usePanelContext, s as useMessagePipeline, v as v4, t as useHoverValue, w as useSetHoverValue, x as useClearHoverValue, y as useMessagePipelineGetter, z as usePanelSettingsTreeUpdate, B as PlayerCapabilities, C as assertNever, D as PlayerPresence, F as isEqual, G as isDesktopApp, H as createTheme, I as propTypesExports } from './index-BuRQ7ljn.js';
7
7
  import { MosaicDragType, MosaicContext, MosaicWindowContext, getOtherBranch, getNodeAtPath } from 'react-mosaic-component';
8
8
  import { t as typescript } from './useMessageReducer-jNx5e6JW.js';
9
9
  import { g as getDefaultExportFromCjs, c as commonjsGlobal, a as getAugmentedNamespace } from './_commonjsHelpers-E-ZsRS8r.js';
@@ -33240,12 +33240,69 @@ function getAnnotationAtPath(message, path) {
33240
33240
  // License, v2.0. If a copy of the MPL was not distributed with this
33241
33241
  // file, You can obtain one at http://mozilla.org/MPL/2.0/
33242
33242
 
33243
- const TIMESTAMP_ERROR_NS = 15_000_000;
33243
+ const CLEANUP_EVENTS_OLDER_THAN_MS = 1_000 * 5; // 5 seconds
33244
+ const ANNOTATIONS_METRICS_KEY = "annotations";
33245
+ const ANNOTATIONS_EVENT_CAP = 100;
33246
+
33247
+ // FIXME: Use the one from visualizer lib -> probably will have to refactor the whole thing to allow imports from lib which depends on this package :(
33248
+ class EventMetricsManager {
33249
+ metrics = {};
33250
+ registerEvent(topic) {
33251
+ const currentTime = performance.now();
33252
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
33253
+ this.metrics[topic] ??= [];
33254
+ this.metrics[topic].unshift(currentTime);
33255
+ if (this.metrics[topic].length > ANNOTATIONS_EVENT_CAP) {
33256
+ this.metrics[topic].length = ANNOTATIONS_EVENT_CAP;
33257
+ }
33258
+ }
33259
+ calculate(topic) {
33260
+ this.removeOldEvents(topic);
33261
+ const topicMetrics = this.metrics[topic];
33262
+ if (!topicMetrics) {
33263
+ return 0;
33264
+ }
33265
+ let totalInterval = 0;
33266
+ for (let i = 1; i < topicMetrics.length; ++i) {
33267
+ totalInterval += topicMetrics[i - 1] - topicMetrics[i];
33268
+ }
33269
+ if (isNaN(totalInterval)) {
33270
+ return 0;
33271
+ }
33272
+ const fps = 1_000 / (totalInterval / (topicMetrics.length - 1));
33273
+ return Math.round(fps);
33274
+ }
33275
+
33276
+ // Remove events which are older than CLEANUP_EVENTS_OLDER_THAN_MS
33277
+ removeOldEvents(topic) {
33278
+ const now = performance.now();
33279
+ if (this.metrics[topic]) {
33280
+ // biome-ignore lint/style/noNonNullAssertion: can't be null
33281
+ this.metrics[topic] = this.metrics[topic].filter(event => {
33282
+ const diff = now - event;
33283
+ return diff < CLEANUP_EVENTS_OLDER_THAN_MS;
33284
+ });
33285
+ }
33286
+ }
33287
+ }
33288
+ const TIMESTAMP_ERROR_NS = 100_000_000n; // 0.1 seconds
33289
+
33244
33290
  function timeEqualWithError(left, right) {
33245
- const secDiff = Math.abs(left.sec - right.sec);
33246
- if (secDiff !== 0) return false;
33247
- const nsecDiff = Math.abs(left.nsec - right.nsec);
33248
- return nsecDiff <= TIMESTAMP_ERROR_NS;
33291
+ // Convert both timestamps to nanoseconds
33292
+ const leftNs = dist$3.toNanoSec({
33293
+ sec: left.sec,
33294
+ nsec: left.nsec
33295
+ });
33296
+ const rightNs = dist$3.toNanoSec({
33297
+ sec: right.sec,
33298
+ nsec: right.nsec
33299
+ });
33300
+
33301
+ // Get absolute difference while staying in bigint
33302
+ const diffNs = leftNs > rightNs ? leftNs - rightNs : rightNs - leftNs;
33303
+
33304
+ // Convert TIMESTAMP_ERROR_NS to bigint for comparison
33305
+ return diffNs <= TIMESTAMP_ERROR_NS;
33249
33306
  }
33250
33307
 
33251
33308
  // Have constants for the HUD items so that they don't need to be recreated and GCed every message
@@ -33273,6 +33330,7 @@ const WAITING_FOR_IMAGE_EMPTY_HUD_ITEM = {
33273
33330
  getMessage: () => t3D("waitingForImages"),
33274
33331
  displayType: "empty"
33275
33332
  };
33333
+
33276
33334
  /**
33277
33335
  * Processes and normalizes incoming messages and manages state of
33278
33336
  * messages to be rendered given the ImageMode config. A large part of this responsibility
@@ -33304,6 +33362,11 @@ class MessageHandler {
33304
33362
  * with no indication to the user that the annotation is not available.
33305
33363
  */
33306
33364
  #availableAnnotationTopics;
33365
+ #onAnnotationsFpsUpdate;
33366
+ #annotationsFpsMetrics = new EventMetricsManager();
33367
+ #annotationsFpsRefreshInterval = null;
33368
+ #averageAnnotationsFps = 0;
33369
+ #ghostAnnotation = undefined;
33307
33370
 
33308
33371
  /**
33309
33372
  *
@@ -33317,10 +33380,25 @@ class MessageHandler {
33317
33380
  };
33318
33381
  this.#tree = new dist$1.AVLTree(dist$3.compare);
33319
33382
  this.#availableAnnotationTopics = new Set();
33383
+ this.#annotationsFpsRefreshInterval = setInterval(() => {
33384
+ const newAverageAnnotationsFps = this.#annotationsFpsMetrics.calculate(ANNOTATIONS_METRICS_KEY);
33385
+ this.#averageAnnotationsFps = newAverageAnnotationsFps;
33386
+ if (this.#onAnnotationsFpsUpdate) {
33387
+ this.#onAnnotationsFpsUpdate(newAverageAnnotationsFps);
33388
+ }
33389
+ }, 500);
33390
+ }
33391
+ dispose() {
33392
+ if (this.#annotationsFpsRefreshInterval) {
33393
+ clearInterval(this.#annotationsFpsRefreshInterval);
33394
+ }
33320
33395
  }
33321
33396
  addListener(listener) {
33322
33397
  this.#listeners.push(listener);
33323
33398
  }
33399
+ addOnAnnotationsFpsUpdateListener(listener) {
33400
+ this.#onAnnotationsFpsUpdate = listener;
33401
+ }
33324
33402
  removeListener(listener) {
33325
33403
  this.#listeners = this.#listeners.filter(fn => fn !== listener);
33326
33404
  }
@@ -33392,6 +33470,11 @@ class MessageHandler {
33392
33470
  };
33393
33471
  handleAnnotations = messageEvent => {
33394
33472
  const annotations = normalizeAnnotations(messageEvent.message, messageEvent.schemaName);
33473
+
33474
+ // We only want to log Annotations event if the array is not empty
33475
+ if (annotations.length > 0) {
33476
+ this.#annotationsFpsMetrics.registerEvent(ANNOTATIONS_METRICS_KEY);
33477
+ }
33395
33478
  const {
33396
33479
  topic
33397
33480
  } = messageEvent;
@@ -33404,6 +33487,8 @@ class MessageHandler {
33404
33487
  return;
33405
33488
  }
33406
33489
  const groups = new Map();
33490
+
33491
+ // Group annotation by timestamp
33407
33492
  for (const annotation of annotations) {
33408
33493
  const key = dist$3.toNanoSec(annotation.stamp);
33409
33494
  const arr = groups.get(key);
@@ -33430,6 +33515,9 @@ class MessageHandler {
33430
33515
  });
33431
33516
  }
33432
33517
  }
33518
+
33519
+ //console.error("Tree after adding annotations", [...this.#tree.entries()]);
33520
+
33433
33521
  this.#emitState();
33434
33522
  };
33435
33523
  setConfig(newConfig) {
@@ -33519,24 +33607,37 @@ class MessageHandler {
33519
33607
  this.#hud.displayIfTrue(waitingForImage && calibrationRequired, WAITING_FOR_IMAGE_NOTICE_HUD_ITEM);
33520
33608
  }
33521
33609
  #getRenderState() {
33522
- if (this.#config.synchronize === true) {
33523
- const result = findSynchronizedSetAndRemoveOlderItems(this.#tree, this.#visibleAnnotations());
33524
- if (result.found) {
33525
- return {
33526
- cameraInfo: this.#lastReceivedMessages.cameraInfo,
33527
- image: result.messages.image,
33528
- annotationsByTopic: result.messages.annotationsByTopic
33529
- };
33530
- }
33610
+ if (this.#config.synchronize !== true) {
33531
33611
  return {
33532
- cameraInfo: this.#lastReceivedMessages.cameraInfo,
33533
- presentAnnotationTopics: result.presentAnnotationTopics,
33534
- missingAnnotationTopics: result.missingAnnotationTopics
33612
+ ...this.#lastReceivedMessages
33535
33613
  };
33536
33614
  }
33537
- return {
33538
- ...this.#lastReceivedMessages
33615
+ const result = findSynchronizedSetAndRemoveOlderItems(this.#tree, this.#visibleAnnotations());
33616
+
33617
+ // If there were matching annotations we want to update Ghost annotation to last known annotations
33618
+ const now = performance.now();
33619
+ if (result.found && result.messages.annotationsByTopic.size > 0) {
33620
+ //console.warn("Registering ghost annotation", result.messages.annotationsByTopic);
33621
+ this.#ghostAnnotation = {
33622
+ annotations: result.messages.annotationsByTopic,
33623
+ createdAtMs: now
33624
+ };
33625
+ }
33626
+ const renderState = result.found ? {
33627
+ cameraInfo: this.#lastReceivedMessages.cameraInfo,
33628
+ image: result.messages.image,
33629
+ annotationsByTopic: result.messages.annotationsByTopic
33630
+ } : {
33631
+ cameraInfo: this.#lastReceivedMessages.cameraInfo,
33632
+ presentAnnotationTopics: result.presentAnnotationTopics,
33633
+ missingAnnotationTopics: result.missingAnnotationTopics
33539
33634
  };
33635
+ const ghostTimeMs = annoationsFpsToGhostTimeMs(this.#averageAnnotationsFps);
33636
+ if (result.found && [...result.messages.annotationsByTopic.values()].length === 0 && this.#ghostAnnotation && now - this.#ghostAnnotation.createdAtMs < ghostTimeMs) {
33637
+ console.warn(`No annotations found for this frame but still in ghost period (diff = ${now - this.#ghostAnnotation.createdAtMs} ms, ghostTimeMs = ${ghostTimeMs} ms) - returning ghost annotation`);
33638
+ renderState.annotationsByTopic = this.#ghostAnnotation.annotations;
33639
+ }
33640
+ return renderState;
33540
33641
  }
33541
33642
  }
33542
33643
  const ACCEPT_LAST_INDEX = 5;
@@ -33549,40 +33650,61 @@ const ACCEPT_LAST_INDEX = 5;
33549
33650
  */
33550
33651
  function findSynchronizedSetAndRemoveOlderItems(tree, visibleAnnotations) {
33551
33652
  let lastEntry = undefined;
33552
-
33553
- // Find ACCEPT_LAST_INDEX frame from the end
33653
+ let lastAnnotationsOrphanEntry = undefined;
33654
+ let validEntry = undefined;
33554
33655
  let imageEntries = 0;
33656
+
33657
+ // Calculate number of entries that have images
33555
33658
  for (const entry of tree.entries()) {
33556
33659
  if (entry[1].image) {
33557
33660
  imageEntries += 1;
33558
33661
  lastEntry = entry;
33662
+ } else if (entry[1].annotationsByTopic.size > 0) {
33663
+ // If there are annotations we want to use the last entry with annotations
33664
+ lastAnnotationsOrphanEntry = entry;
33559
33665
  }
33560
33666
  }
33561
- let validEntry = undefined;
33562
- if (visibleAnnotations.size !== 0) {
33667
+
33668
+ // If there are no annotations active we use the newest entry with image
33669
+ if (visibleAnnotations.size === 0) {
33670
+ validEntry = lastEntry;
33671
+ } else {
33672
+ // Else we try to find first
33563
33673
  let acceptableIndex = imageEntries - ACCEPT_LAST_INDEX + 1;
33674
+ // console.warn("acceptableIndex", acceptableIndex);
33675
+
33564
33676
  if (acceptableIndex < 0) {
33565
33677
  acceptableIndex = 0;
33566
33678
  }
33567
33679
  let index = 0;
33680
+
33681
+ // Go throught the tree in order and find first entry that has image and all annotations
33568
33682
  for (const entry of tree.entries()) {
33683
+ // Skip entries with no images
33569
33684
  if (!entry[1].image) {
33570
33685
  continue;
33571
33686
  }
33687
+
33688
+ // When we encounter the first acceptable index we use that as the entry
33572
33689
  if (index === acceptableIndex) {
33573
33690
  validEntry = entry;
33574
33691
  } else if (index > acceptableIndex) {
33692
+ // Any bigger index with all annotations which is newer than already used index is the better option
33575
33693
  const hasAllAnnotations = Array.from(visibleAnnotations).every(topic => entry[1].annotationsByTopic.has(topic));
33576
33694
  if (hasAllAnnotations) {
33695
+ console.warn("upgrading to new valid entry", entry);
33577
33696
  validEntry = entry;
33578
33697
  }
33579
33698
  }
33580
33699
  index += 1;
33581
33700
  }
33582
- } else {
33583
- validEntry = lastEntry;
33584
33701
  }
33585
33702
  if (validEntry) {
33703
+ if (validEntry[1].annotationsByTopic.size === 0 && lastAnnotationsOrphanEntry) {
33704
+ console.warn("Using annotationsByTopic from lastAnnotationsEntry orphan");
33705
+ validEntry[1].annotationsByTopic = lastAnnotationsOrphanEntry[1].annotationsByTopic;
33706
+ }
33707
+
33586
33708
  // Drop older messages
33587
33709
  let minKey = tree.minKey();
33588
33710
  while (minKey && dist$3.isLessThan(minKey, validEntry[0])) {
@@ -33600,6 +33722,13 @@ function findSynchronizedSetAndRemoveOlderItems(tree, visibleAnnotations) {
33600
33722
  presentAnnotationTopics: []
33601
33723
  };
33602
33724
  }
33725
+ function annoationsFpsToGhostTimeMs(annotationsFps) {
33726
+ if (annotationsFps === undefined || annotationsFps === 0 || !Number.isFinite(annotationsFps)) {
33727
+ return 1_000; // If there is no annotations fps, we want set the ghost time to 1 second
33728
+ }
33729
+ const period = 1 / annotationsFps;
33730
+ return period * 1_000 * 2; // To miliseconds times two
33731
+ }
33603
33732
 
33604
33733
  // This Source Code Form is subject to the terms of the Mozilla Public
33605
33734
  // License, v2.0. If a copy of the MPL was not distributed with this
@@ -34952,6 +35081,7 @@ class ImageMode extends SceneExtension {
34952
35081
  this.renderer.off("topicsChanged", this.#handleTopicsChanged);
34953
35082
  this.#annotations.dispose();
34954
35083
  this.imageRenderable?.dispose();
35084
+ this.messageHandler?.dispose?.();
34955
35085
  super.dispose();
34956
35086
  }
34957
35087
  removeAllRenderables() {
@@ -35590,6 +35720,9 @@ class ImageMode extends SceneExtension {
35590
35720
  disabled: this.imageRenderable?.getDecodedImage() == undefined
35591
35721
  }];
35592
35722
  }
35723
+ addOnAnnotationsFpsUpdateListener(listener) {
35724
+ this.messageHandler.addOnAnnotationsFpsUpdateListener(listener);
35725
+ }
35593
35726
  setOnImageRendered(callback) {
35594
35727
  this.#onImageRendered = callback;
35595
35728
  }
@@ -60054,9 +60187,10 @@ class CameraStateSettings extends SceneExtension {
60054
60187
  this.#controls.dampingFactor = 0.05;
60055
60188
  this.#controls.mouseButtons.left = CameraControls.ACTION.NONE;
60056
60189
  this.#controls.mouseButtons.right = CameraControls.ACTION.TRUCK;
60057
- this.#controls.mouseButtons.wheel = CameraControls.ACTION.ZOOM;
60190
+ this.#controls.mouseButtons.wheel = CameraControls.ACTION.DOLLY;
60058
60191
  this.#controls.touches.one = CameraControls.ACTION.TOUCH_SCREEN_PAN;
60059
60192
  this.#controls.infinityDolly = true;
60193
+ this.#controls.dollySpeed = 0.25;
60060
60194
  this.#perspectiveCamera.rotation.set(0, Math.PI, Math.PI);
60061
60195
  this.#perspectiveCamera.up.set(0, 1, 0);
60062
60196
  this.#controls.update(0);
@@ -61128,6 +61262,9 @@ class Renderer extends EventEmitter {
61128
61262
  if (args.onFrameRendered) {
61129
61263
  this.#imageModeExtension.setOnImageRendered(args.onFrameRendered);
61130
61264
  }
61265
+ if (args.annotationsFpsUpdateHandler) {
61266
+ this.#imageModeExtension.addOnAnnotationsFpsUpdateListener(args.annotationsFpsUpdateHandler);
61267
+ }
61131
61268
  this.cameraHandler = this.#imageModeExtension;
61132
61269
  this.#imageModeExtension.addEventListener("hasModifiedViewChanged", () => {
61133
61270
  this.emit("resetViewChanged", this);
@@ -78833,7 +78970,9 @@ function ThreeDeeRender(props) {
78833
78970
  context,
78834
78971
  interfaceMode,
78835
78972
  testOptions,
78836
- customSceneExtensions
78973
+ customSceneExtensions,
78974
+ frameRenderedEvent,
78975
+ annotationsFpsUpdateHandler
78837
78976
  } = props;
78838
78977
  const {
78839
78978
  initialState,
@@ -78858,9 +78997,7 @@ function ThreeDeeRender(props) {
78858
78997
  scene: {
78859
78998
  ...(partialConfig?.scene ?? {}),
78860
78999
  transforms: {
78861
- showlabels: true,
78862
- editable: true,
78863
- axisScale: 500
79000
+ editable: true
78864
79001
  }
78865
79002
  },
78866
79003
  transforms,
@@ -78897,7 +79034,8 @@ function ThreeDeeRender(props) {
78897
79034
  sceneExtensionConfig: merge$1({}, DEFAULT_SCENE_EXTENSION_CONFIG, customSceneExtensions ?? {}),
78898
79035
  displayTemporaryError,
78899
79036
  testOptions,
78900
- onFrameRendered: props.frameRenderedEvent
79037
+ onFrameRendered: frameRenderedEvent,
79038
+ annotationsFpsUpdateHandler: annotationsFpsUpdateHandler
78901
79039
  }) : undefined;
78902
79040
  setRenderer(newRenderer);
78903
79041
  rendererRef.current = newRenderer;
@@ -79477,7 +79615,8 @@ function initPanel(args, context) {
79477
79615
  interfaceMode,
79478
79616
  testOptions,
79479
79617
  customSceneExtensions,
79480
- frameRenderedEvent
79618
+ frameRenderedEvent,
79619
+ annotationsFpsUpdateHandler
79481
79620
  } = args;
79482
79621
  // eslint-disable-next-line react/no-deprecated
79483
79622
  ReactDOM__default.render( /*#__PURE__*/React__default.createElement(StrictMode, null, /*#__PURE__*/React__default.createElement(CaptureErrorBoundary, {
@@ -79489,7 +79628,8 @@ function initPanel(args, context) {
79489
79628
  interfaceMode: interfaceMode,
79490
79629
  testOptions: testOptions,
79491
79630
  customSceneExtensions: customSceneExtensions,
79492
- frameRenderedEvent: frameRenderedEvent ? () => frameRenderedEvent(0) : undefined
79631
+ frameRenderedEvent: frameRenderedEvent ? () => frameRenderedEvent(0) : undefined,
79632
+ annotationsFpsUpdateHandler: annotationsFpsUpdateHandler
79493
79633
  })))), context.panelElement);
79494
79634
  return () => {
79495
79635
  // eslint-disable-next-line react/no-deprecated
@@ -79518,8 +79658,9 @@ function ThreeDeeRenderAdapter(interfaceMode, props) {
79518
79658
  debugPicking: props.debugPicking
79519
79659
  },
79520
79660
  customSceneExtensions,
79521
- frameRenderedEvent: props.frameRenderedEvent
79522
- }), [crash, forwardedAnalytics, interfaceMode, props.onDownloadImage, props.debugPicking, props.frameRenderedEvent, customSceneExtensions]);
79661
+ frameRenderedEvent: props.frameRenderedEvent,
79662
+ annotationsFpsUpdateHandler: props.annotationsFpsUpdateHandler
79663
+ }), [crash, forwardedAnalytics, interfaceMode, props.onDownloadImage, props.debugPicking, props.frameRenderedEvent, props.annotationsFpsUpdateHandler, customSceneExtensions]);
79523
79664
  return /*#__PURE__*/React__default.createElement(PanelExtensionAdapter, {
79524
79665
  config: props.config,
79525
79666
  highestSupportedConfigVersion: 1,
@@ -1,4 +1,4 @@
1
- import { N as styleTags, O as tags, V as LRParser, Q as LRLanguage, J as indentNodeProp, K as continuedIndent, $ as flatIndent, a0 as delimitedIndent, M as foldNodeProp, a1 as foldInside, T as LanguageSupport } from './index-CPTbtbj3.js';
1
+ import { N as styleTags, O as tags, V as LRParser, Q as LRLanguage, J as indentNodeProp, K as continuedIndent, $ as flatIndent, a0 as delimitedIndent, M as foldNodeProp, a1 as foldInside, T as LanguageSupport } from './index-BuRQ7ljn.js';
2
2
  import './tslib.es6-C73eoP_E.js';
3
3
  import 'react';
4
4
  import 'react-mosaic-component';
@@ -1,4 +1,4 @@
1
- import { J as indentNodeProp, K as continuedIndent, M as foldNodeProp, N as styleTags, O as tags, Q as LRLanguage, T as LanguageSupport, U as ExternalTokenizer, V as LRParser, X as ifNotIn, Y as completeFromList, Z as syntaxTree } from './index-CPTbtbj3.js';
1
+ import { J as indentNodeProp, K as continuedIndent, M as foldNodeProp, N as styleTags, O as tags, Q as LRLanguage, T as LanguageSupport, U as ExternalTokenizer, V as LRParser, X as ifNotIn, Y as completeFromList, Z as syntaxTree } from './index-BuRQ7ljn.js';
2
2
  import './tslib.es6-C73eoP_E.js';
3
3
  import 'react';
4
4
  import 'react-mosaic-component';
@@ -1,4 +1,4 @@
1
- import { a2 as ContextTracker, U as ExternalTokenizer, N as styleTags, O as tags, V as LRParser, Q as LRLanguage, J as indentNodeProp, a0 as delimitedIndent, M as foldNodeProp, a1 as foldInside, T as LanguageSupport, ab as parseMixed } from './index-CPTbtbj3.js';
1
+ import { a2 as ContextTracker, U as ExternalTokenizer, N as styleTags, O as tags, V as LRParser, Q as LRLanguage, J as indentNodeProp, a0 as delimitedIndent, M as foldNodeProp, a1 as foldInside, T as LanguageSupport, ab as parseMixed } from './index-BuRQ7ljn.js';
2
2
  import './tslib.es6-C73eoP_E.js';
3
3
  import 'react';
4
4
  import 'react-mosaic-component';
@@ -1,4 +1,4 @@
1
- import { U as ExternalTokenizer, N as styleTags, O as tags, V as LRParser, Q as LRLanguage, J as indentNodeProp, K as continuedIndent, a0 as delimitedIndent, M as foldNodeProp, a1 as foldInside, aa as html, T as LanguageSupport, ab as parseMixed } from './index-CPTbtbj3.js';
1
+ import { U as ExternalTokenizer, N as styleTags, O as tags, V as LRParser, Q as LRLanguage, J as indentNodeProp, K as continuedIndent, a0 as delimitedIndent, M as foldNodeProp, a1 as foldInside, aa as html, T as LanguageSupport, ab as parseMixed } from './index-BuRQ7ljn.js';
2
2
  import './tslib.es6-C73eoP_E.js';
3
3
  import 'react';
4
4
  import 'react-mosaic-component';
@@ -1,4 +1,4 @@
1
- import { U as ExternalTokenizer, N as styleTags, O as tags, V as LRParser, Q as LRLanguage, J as indentNodeProp, K as continuedIndent, $ as flatIndent, a0 as delimitedIndent, M as foldNodeProp, a1 as foldInside, T as LanguageSupport } from './index-CPTbtbj3.js';
1
+ import { U as ExternalTokenizer, N as styleTags, O as tags, V as LRParser, Q as LRLanguage, J as indentNodeProp, K as continuedIndent, $ as flatIndent, a0 as delimitedIndent, M as foldNodeProp, a1 as foldInside, T as LanguageSupport } from './index-BuRQ7ljn.js';
2
2
  import './tslib.es6-C73eoP_E.js';
3
3
  import 'react';
4
4
  import 'react-mosaic-component';
@@ -1,4 +1,4 @@
1
- import { N as styleTags, O as tags, ad as javascriptLanguage, Q as LRLanguage, T as LanguageSupport, V as LRParser, aa as html, ab as parseMixed, U as ExternalTokenizer } from './index-CPTbtbj3.js';
1
+ import { N as styleTags, O as tags, ad as javascriptLanguage, Q as LRLanguage, T as LanguageSupport, V as LRParser, aa as html, ab as parseMixed, U as ExternalTokenizer } from './index-BuRQ7ljn.js';
2
2
  import './tslib.es6-C73eoP_E.js';
3
3
  import 'react';
4
4
  import 'react-mosaic-component';
@@ -1,4 +1,4 @@
1
- import { U as ExternalTokenizer, a2 as ContextTracker, N as styleTags, O as tags, V as LRParser, a3 as LocalTokenGroup, a4 as snippetCompletion, Z as syntaxTree, Q as LRLanguage, J as indentNodeProp, K as continuedIndent, $ as flatIndent, a0 as delimitedIndent, M as foldNodeProp, a1 as foldInside, T as LanguageSupport, X as ifNotIn, Y as completeFromList, a5 as IterMode, a6 as NodeWeakMap } from './index-CPTbtbj3.js';
1
+ import { U as ExternalTokenizer, a2 as ContextTracker, N as styleTags, O as tags, V as LRParser, a3 as LocalTokenGroup, a4 as snippetCompletion, Z as syntaxTree, Q as LRLanguage, J as indentNodeProp, K as continuedIndent, $ as flatIndent, a0 as delimitedIndent, M as foldNodeProp, a1 as foldInside, T as LanguageSupport, X as ifNotIn, Y as completeFromList, a5 as IterMode, a6 as NodeWeakMap } from './index-BuRQ7ljn.js';
2
2
  import './tslib.es6-C73eoP_E.js';
3
3
  import 'react';
4
4
  import 'react-mosaic-component';
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- export { ah as ImagePanel, ag as PanelLayout, ai as PointCloudPanel, ae as VisualizerConnection, af as VisualizerContext } from './index-CPTbtbj3.js';
1
+ export { aj as EventMetricsManager, ah as ImagePanel, ag as PanelLayout, ai as PointCloudPanel, ak as ThroughputMetricsManager, ae as VisualizerConnection, af as VisualizerContext } from './index-BuRQ7ljn.js';
2
2
  import './tslib.es6-C73eoP_E.js';
3
3
  import 'react';
4
4
  import 'react-mosaic-component';
@@ -1,5 +1,5 @@
1
1
  import type { ProtobufKind } from "../messaging/protobuf.js";
2
- import '../fonts/fonts.css';
2
+ import "../fonts/fonts.css";
3
3
  export type PanelTopic = {
4
4
  name: string;
5
5
  extra: boolean;
@@ -14,6 +14,7 @@ export type PanelProps = React.PropsWithChildren<{
14
14
  targetFps?: number;
15
15
  triggerToast?: () => void;
16
16
  renderedFps?: number;
17
+ annotationsFps?: number;
17
18
  renderDelay?: number;
18
19
  toggleTopic?: (topic: string) => void;
19
20
  }>;
@@ -1 +1 @@
1
- {"version":3,"file":"Panel.d.ts","sourceRoot":"","sources":["../../../../src/components/Panel.tsx"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAE7D,OAAO,oBAAoB,CAAC;AAE5B,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG,KAAK,CAAC,iBAAiB,CAAC;IAC/C,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,YAAY,CAAC;IACnB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,qBAAqB,CAAC,EAAE,MAAM,EAAE,CAAC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACvC,CAAC,CAAC;AAEH,MAAM,MAAM,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEtD,MAAM,MAAM,aAAa,GAAG;IAC1B,UAAU,EAAE,UAAU,EAAE,CAAC;CAC1B,CAAC;AAIF,eAAO,MAAM,aAAa,QAAO,aAEhC,CAAC;AASF,eAAO,MAAM,KAAK,EAAE,KAAK,CAAC,EAAE,CAAC,UAAU,CA4DtC,CAAC"}
1
+ {"version":3,"file":"Panel.d.ts","sourceRoot":"","sources":["../../../../src/components/Panel.tsx"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAE7D,OAAO,oBAAoB,CAAC;AAE5B,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG,KAAK,CAAC,iBAAiB,CAAC;IAC/C,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,YAAY,CAAC;IACnB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,qBAAqB,CAAC,EAAE,MAAM,EAAE,CAAC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACvC,CAAC,CAAC;AAEH,MAAM,MAAM,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEtD,MAAM,MAAM,aAAa,GAAG;IAC1B,UAAU,EAAE,UAAU,EAAE,CAAC;CAC1B,CAAC;AAIF,eAAO,MAAM,aAAa,QAAO,aAEhC,CAAC;AAaF,eAAO,MAAM,KAAK,EAAE,KAAK,CAAC,EAAE,CAAC,UAAU,CA8DtC,CAAC"}
@@ -8,27 +8,27 @@ import EmptyState from "@foxglove/studio-base/components/EmptyState.js";
8
8
  import ErrorBoundary from "@foxglove/studio-base/components/ErrorBoundary.js";
9
9
  import RemountOnValueChange from "@foxglove/studio-base/components/RemountOnValueChange.js";
10
10
  import { PanelToolbar } from "./PanelToolbar.js";
11
- import '../fonts/fonts.css';
11
+ import "../fonts/fonts.css";
12
12
  const DetectionContext = React.createContext({ detections: [] });
13
13
  export const useDetections = () => {
14
14
  return React.useContext(DetectionContext);
15
15
  };
16
16
  const rawToAnnotations = (rawAnnotations, kind, current) => rawAnnotations.map((annotationTopic) => ({
17
17
  name: annotationTopic,
18
- extra: kind === 'extra',
19
- enabled: current.find(({ name }) => name === annotationTopic)?.enabled ?? kind === 'main'
18
+ extra: kind === "extra",
19
+ enabled: current.find(({ name }) => name === annotationTopic)?.enabled ?? kind === "main",
20
20
  }));
21
- export const Panel = ({ children, kind, topic, disableAnnotations = false, annotationTopics = [], extraAnnotationTopics = [], targetFps, renderedFps, renderDelay, toggleTopic, triggerToast, }) => {
21
+ export const Panel = ({ children, kind, topic, disableAnnotations = false, annotationTopics = [], extraAnnotationTopics = [], targetFps, renderedFps, annotationsFps, renderDelay, toggleTopic, triggerToast, }) => {
22
22
  const [detections, setDetections] = React.useState([]);
23
23
  React.useEffect(() => {
24
24
  if (!disableAnnotations) {
25
- setDetections(current => [
26
- ...rawToAnnotations(annotationTopics, 'main', current),
27
- ...rawToAnnotations(extraAnnotationTopics, 'extra', current)
25
+ setDetections((current) => [
26
+ ...rawToAnnotations(annotationTopics, "main", current),
27
+ ...rawToAnnotations(extraAnnotationTopics, "extra", current),
28
28
  ]);
29
29
  }
30
30
  // eslint-disable-next-line react-hooks/exhaustive-deps
31
31
  }, [JSON.stringify(annotationTopics), JSON.stringify(extraAnnotationTopics)]);
32
- return (_jsx(RemountOnValueChange, { value: "internal-player", children: _jsx(ErrorBoundary, { children: _jsx(DetectionContext.Provider, { value: { detections }, children: _jsxs(Stack, { flexGrow: 1, overflow: "hidden", border: "1px solid #d3d3d3d9", style: { borderRadius: "8px" }, children: [_jsx(PanelToolbar, { kind: kind, topic: topic, setDetections: setDetections, disableAnnotations: disableAnnotations, targetFps: targetFps, renderedFps: renderedFps, renderDelay: renderDelay, toggleTopic: toggleTopic, triggerToast: triggerToast }), _jsx(Suspense, { fallback: _jsx(EmptyState, { children: _jsx("div", { children: "Loading..." }) }), children: _jsx(RemountOnValueChange, { value: detections, children: children }) })] }) }) }) }));
32
+ return (_jsx(RemountOnValueChange, { value: "internal-player", children: _jsx(ErrorBoundary, { children: _jsx(DetectionContext.Provider, { value: { detections }, children: _jsxs(Stack, { flexGrow: 1, overflow: "hidden", border: "1px solid #d3d3d3d9", style: { borderRadius: "8px" }, children: [_jsx(PanelToolbar, { kind: kind, topic: topic, setDetections: setDetections, disableAnnotations: disableAnnotations, targetFps: targetFps, renderedFps: renderedFps, annotationsFps: annotationsFps, renderDelay: renderDelay, toggleTopic: toggleTopic, triggerToast: triggerToast }), _jsx(Suspense, { fallback: _jsx(EmptyState, { children: _jsx("div", { children: "Loading..." }) }), children: _jsx(RemountOnValueChange, { value: detections, children: children }) })] }) }) }) }));
33
33
  };
34
34
  //# sourceMappingURL=Panel.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Panel.js","sourceRoot":"","sources":["../../../../src/components/Panel.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Panel.js","sourceRoot":"","sources":["../../../../src/components/Panel.tsx"],"names":[],"mappings":"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"}
@@ -9,6 +9,7 @@ export type PanelToolbarProps = {
9
9
  setDetections?: (cb: (topics: PanelTopic[]) => PanelTopic[]) => void;
10
10
  targetFps?: number;
11
11
  renderedFps?: number;
12
+ annotationsFps?: number;
12
13
  renderDelay?: number;
13
14
  triggerToast?: () => void;
14
15
  toggleTopic?: (topic: string) => void;
@@ -1 +1 @@
1
- {"version":3,"file":"PanelToolbar.d.ts","sourceRoot":"","sources":["../../../../src/components/PanelToolbar.tsx"],"names":[],"mappings":"AAGA,OAAO,eAAe,CAAC;AAuBvB,OAAO,EAAE,KAAK,UAAU,EAAiB,MAAM,YAAY,CAAC;AAG5D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,sCAAsC,CAAC;AAqI9C,MAAM,MAAM,iBAAiB,GAAG;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,YAAY,CAAC;IACnB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,aAAa,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,UAAU,EAAE,KAAK,IAAI,CAAC;IACrE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACvC,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAgLpD,CAAC"}
1
+ {"version":3,"file":"PanelToolbar.d.ts","sourceRoot":"","sources":["../../../../src/components/PanelToolbar.tsx"],"names":[],"mappings":"AAGA,OAAO,eAAe,CAAC;AAuBvB,OAAO,EAAE,KAAK,UAAU,EAAiB,MAAM,YAAY,CAAC;AAG5D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,sCAAsC,CAAC;AA0J9C,MAAM,MAAM,iBAAiB,GAAG;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,YAAY,CAAC;IACnB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,aAAa,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,UAAU,EAAE,KAAK,IAAI,CAAC;IACrE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACvC,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAuLpD,CAAC"}
@@ -11,7 +11,7 @@ import { useConnections } from "../context/ConnectionsProvider.js";
11
11
  import "@luxonis/common-fe-components/styles";
12
12
  import { createEventLoopDelaySampler } from "./measure-event-loop-delay";
13
13
  import { RiNumbersFill } from "react-icons/ri";
14
- function PanelToolbarMetrics({ renderedFps, targetFps, metrics }) {
14
+ function PanelToolbarMetrics({ renderedFps, annotationsFps, targetFps, metrics, }) {
15
15
  const [variant, setVariant] = React.useState("full");
16
16
  const eventLoopDelay = createEventLoopDelaySampler();
17
17
  const descriptionRef = React.useRef(null);
@@ -23,7 +23,12 @@ function PanelToolbarMetrics({ renderedFps, targetFps, metrics }) {
23
23
  setVariant("full");
24
24
  }
25
25
  }, [descriptionRef.current?.offsetWidth]);
26
- return (_jsx(Flex, { direction: "row", gap: "sm", align: "start", justify: "end", ref: descriptionRef, width: "full", children: variant === "compact" ? (_jsx(Tooltip, { content: _jsxs("ul", { children: [_jsxs("li", { children: ["Camera: ", targetFps === 0 ? "-" : targetFps, " FPS"] }), _jsxs("li", { children: ["Network:", " ", !metrics || metrics?.incomingMessagesFps === 0 ? "-" : metrics.incomingMessagesFps, " ", "FPS"] }), _jsxs("li", { children: ["Decoding:", " ", !metrics || metrics?.decodedMessagesFps === 0 ? "-" : metrics.decodedMessagesFps, " ", "FPS"] }), _jsxs("li", { children: ["Rendering: ", renderedFps === 0 ? "-" : renderedFps, " FPS"] }), _jsxs("li", { children: ["Throughput:", " ", !metrics || metrics?.messageThroughput === 0 ? "-" : metrics.messageThroughput, " ", "Mbps"] }), _jsxs("li", { children: ["Frontend Delay: ", eventLoopDelay.toFixed(2), " ms"] })] }), direction: "bottom", className: "ml-auto", children: _jsx(Button, { icon: RiNumbersFill, variant: "outline", colorVariant: "white", size: "sm", className: "text-gray-700" }) })) : (_jsxs(_Fragment, { children: [targetFps !== undefined && (_jsx(Label, { text: `Camera: ${targetFps === 0 ? "-" : targetFps} FPS` })), metrics?.incomingMessagesFps !== undefined && (_jsx(Label, { text: `Network: ${metrics.incomingMessagesFps === 0 ? "-" : metrics.incomingMessagesFps} FPS` })), metrics?.decodedMessagesFps !== undefined && (_jsx(Label, { text: `Decoding: ${metrics.decodedMessagesFps === 0 ? "-" : metrics.decodedMessagesFps} FPS` })), renderedFps !== undefined && (_jsx(Label, { text: `Rendering: ${renderedFps === 0 ? "-" : renderedFps} FPS` })), metrics?.messageThroughput !== undefined && (_jsx(Label, { text: `Throughput: ${metrics.messageThroughput === 0 ? "-" : metrics.messageThroughput} Mbps` })), eventLoopDelay !== undefined && (_jsx(Label, { text: `Frontend Delay: ${Math.ceil(eventLoopDelay)} ms` }))] })) }));
26
+ return (_jsx(Flex, { direction: "row", gap: "sm", align: "start", justify: "end", ref: descriptionRef, width: "full", children: variant === "compact" ? (_jsx(Tooltip, { content: _jsxs("ul", { children: [_jsxs("li", { children: ["Camera: ", !targetFps || targetFps === 0 ? "-" : targetFps, " FPS"] }), _jsxs("li", { children: ["Network:", " ", !metrics || metrics?.incomingMessagesFps === 0 ? "-" : metrics.incomingMessagesFps, " ", "FPS"] }), _jsxs("li", { children: ["Decoding:", " ", !metrics || metrics?.decodedMessagesFps === 0 ? "-" : metrics.decodedMessagesFps, " ", "FPS"] }), _jsxs("li", { children: ["Rendering: ", !renderedFps || renderedFps === 0 ? "-" : renderedFps, " FPS"] }), _jsxs("li", { children: ["Annotations:", " ", !annotationsFps ||
27
+ annotationsFps === 0 ||
28
+ !Number.isFinite(annotationsFps)
29
+ ? "-"
30
+ : annotationsFps, " ", "FPS"] }), _jsxs("li", { children: ["Throughput:", " ", !metrics || metrics?.messageThroughput === 0 ? "-" : metrics.messageThroughput, " ", "Mbps"] }), _jsxs("li", { children: ["Frontend Delay: ", eventLoopDelay.toFixed(2), " ms"] })] }), direction: "bottom", className: "ml-auto", children: _jsx(Button, { icon: RiNumbersFill, variant: "outline", colorVariant: "white", size: "sm", className: "text-gray-700" }) })) : (_jsxs(_Fragment, { children: [targetFps !== undefined && (_jsx(Label, { text: `Camera: ${targetFps === 0 ? "-" : targetFps} FPS` })), metrics?.incomingMessagesFps !== undefined && (_jsx(Label, { text: `Network: ${metrics.incomingMessagesFps === 0 ? "-" : metrics.incomingMessagesFps} FPS` })), metrics?.decodedMessagesFps !== undefined && (_jsx(Label, { text: `Decoding: ${metrics.decodedMessagesFps === 0 ? "-" : metrics.decodedMessagesFps} FPS` })), renderedFps !== undefined && (_jsx(Label, { text: `Rendering: ${renderedFps === 0 ? "-" : renderedFps} FPS` })), annotationsFps !== undefined && (_jsx(Label, { text: `Annotations: ${annotationsFps === 0 ||
31
+ !Number.isFinite(annotationsFps) ? "-" : annotationsFps} FPS` })), metrics?.messageThroughput !== undefined && (_jsx(Label, { text: `Throughput: ${metrics.messageThroughput === 0 ? "-" : metrics.messageThroughput} Mbps` })), eventLoopDelay !== undefined && (_jsx(Label, { text: `Frontend Delay: ${Math.ceil(eventLoopDelay)} ms` }))] })) }));
27
32
  }
28
33
  const PanelAnnotationButton = ({ topic, onClick }) => {
29
34
  const handleClick = React.useCallback((event) => {
@@ -32,7 +37,7 @@ const PanelAnnotationButton = ({ topic, onClick }) => {
32
37
  }, [onClick]);
33
38
  return (_jsx(DropdownMenuItem, { onClick: handleClick, children: _jsxs(Flex, { align: "center", gap: "sm", children: [_jsx(Icon, { color: "active", icon: topic.enabled ? ImCheckboxChecked : ImCheckboxUnchecked }), _jsx(NormalText, { text: topic.name })] }) }));
34
39
  };
35
- export const PanelToolbar = ({ topic, kind, setDetections, disableAnnotations = false, targetFps, triggerToast, renderedFps, toggleTopic, }) => {
40
+ export const PanelToolbar = ({ topic, kind, setDetections, disableAnnotations = false, targetFps, triggerToast, renderedFps, annotationsFps, toggleTopic, }) => {
36
41
  const [metrics, setMetrics] = React.useState();
37
42
  const { detections } = useDetections();
38
43
  const connections = useConnections();
@@ -77,7 +82,7 @@ export const PanelToolbar = ({ topic, kind, setDetections, disableAnnotations =
77
82
  const makeDetection = React.useCallback((detection, { extra }) => (extra ? detection.extra && !detection.enabled : !detection.extra || detection.enabled) && (_jsx(PanelAnnotationButton, { topic: detection, onClick: () => {
78
83
  onToggleTopic(detection.name);
79
84
  } }, detection.name)), [onToggleTopic]);
80
- return (_jsx(Flex, { direction: "row", gap: "sm", align: "center", justify: "space-between", className: "px-4", children: _jsxs(Flex, { direction: "row", gap: "xs", align: "center", justify: "start", width: "full", paddingY: "xs", children: [_jsxs(Flex, { width: "fit", gap: "xxs", className: "flex-col xl:flex-row items-start xl:items-end", children: [_jsx(SubHeader, { text: name, className: "whitespace-nowrap text-[20px]/[20px]" }), resolution && _jsx(Label, { text: `(${resolution})`, className: "text-[14px]/[14px] xl:pb-[2px]" })] }), _jsx(PanelToolbarMetrics, { renderedFps: renderedFps, targetFps: targetFps, metrics: metrics }), _jsxs(Flex, { direction: "row", gap: "xs", align: "center", justify: "start", marginLeft: "auto", width: "fit", children: [!disableAnnotations && kind === "image" && (_jsxs(DropdownMenu, { children: [_jsx(Tooltip, { content: "Annotations", children: _jsx(DropdownMenuTrigger, { asChild: true, disabled: detections.length === 0, children: _jsx(Button, { variant: "outline", colorVariant: "white", size: "sm", icon: CiFilter, disabled: detections.length === 0 }) }) }), _jsxs(DropdownMenuContent, { children: [detections.map((detection) => makeDetection(detection, { extra: false })), hasExtra && (_jsx(Button, { width: "full", paddingY: "xs", variant: "ghost", "aria-expanded": extraVisible ? "true" : undefined, onClick: () => {
85
+ return (_jsx(Flex, { direction: "row", gap: "sm", align: "center", justify: "space-between", className: "px-4", children: _jsxs(Flex, { direction: "row", gap: "xs", align: "center", justify: "start", width: "full", paddingY: "xs", children: [_jsxs(Flex, { width: "fit", gap: "xxs", className: "flex-col xl:flex-row items-start xl:items-end", children: [_jsx(SubHeader, { text: name, className: "whitespace-nowrap text-[20px]/[20px]" }), resolution && (_jsx(Label, { text: `(${resolution})`, className: "text-[14px]/[14px] xl:pb-[2px]" }))] }), _jsx(PanelToolbarMetrics, { renderedFps: renderedFps, annotationsFps: annotationsFps, targetFps: targetFps, metrics: metrics }), _jsxs(Flex, { direction: "row", gap: "xs", align: "center", justify: "start", marginLeft: "auto", width: "fit", children: [!disableAnnotations && kind === "image" && (_jsxs(DropdownMenu, { children: [_jsx(Tooltip, { content: "Annotations", children: _jsx(DropdownMenuTrigger, { asChild: true, disabled: detections.length === 0, children: _jsx(Button, { variant: "outline", colorVariant: "white", size: "sm", icon: CiFilter, disabled: detections.length === 0 }) }) }), _jsxs(DropdownMenuContent, { children: [detections.map((detection) => makeDetection(detection, { extra: false })), hasExtra && (_jsx(Button, { width: "full", paddingY: "xs", variant: "ghost", "aria-expanded": extraVisible ? "true" : undefined, onClick: () => {
81
86
  setExtraVisible((current) => !current);
82
87
  }, icon: extraVisible ? ArrowUpIcon : ArrowDownIcon, style: {
83
88
  borderRadius: 4,