timeline-canvas 1.3.1 → 1.4.1

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 (41) hide show
  1. package/README.md +183 -162
  2. package/README_CN.md +185 -164
  3. package/dist/ContextMenuPlugin-DkjzERie.mjs +1 -0
  4. package/dist/{ContextMenuPlugin-DaM7qC-I.d.mts → ContextMenuPlugin-erWC3clR.d.mts} +1 -1
  5. package/dist/{DarkThemePlugin-CbU457K7.d.mts → DarkThemePlugin-DSeernWS.d.mts} +1 -1
  6. package/dist/DarkThemePlugin-oE6DVEib.mjs +1 -0
  7. package/dist/EventMediaPlugin-Co_Fr3CX.mjs +1 -0
  8. package/dist/{EventMediaPlugin-BfZm0W26.d.mts → EventMediaPlugin-DpK2xquj.d.mts} +1 -1
  9. package/dist/{EventTooltipPlugin-D2jEsna_.d.mts → EventTooltipPlugin-B2lXP9uu.d.mts} +1 -1
  10. package/dist/EventTooltipPlugin-mbadM95i.mjs +1 -0
  11. package/dist/LightThemePlugin-BigH_oWz.mjs +1 -0
  12. package/dist/{LightThemePlugin-DAbrMpAs.d.mts → LightThemePlugin-CXkW_Wpg.d.mts} +1 -1
  13. package/dist/{PerformanceOverlayPlugin-B21vlKMn.d.mts → PerformanceOverlayPlugin-CnfsbiMK.d.mts} +1 -1
  14. package/dist/PerformanceOverlayPlugin-o5al1GSm.mjs +1 -0
  15. package/dist/builtin-plugin/ContextMenuPlugin.d.mts +1 -2
  16. package/dist/builtin-plugin/ContextMenuPlugin.mjs +1 -1
  17. package/dist/builtin-plugin/DarkThemePlugin.d.mts +1 -2
  18. package/dist/builtin-plugin/DarkThemePlugin.mjs +1 -1
  19. package/dist/builtin-plugin/EventMediaPlugin.d.mts +1 -2
  20. package/dist/builtin-plugin/EventMediaPlugin.mjs +1 -1
  21. package/dist/builtin-plugin/EventTooltipPlugin.d.mts +1 -2
  22. package/dist/builtin-plugin/EventTooltipPlugin.mjs +1 -1
  23. package/dist/builtin-plugin/LightThemePlugin.d.mts +1 -2
  24. package/dist/builtin-plugin/LightThemePlugin.mjs +1 -1
  25. package/dist/builtin-plugin/MutexGuardPlugin.d.mts +1 -1
  26. package/dist/builtin-plugin/MutexGuardPlugin.mjs +1 -1
  27. package/dist/builtin-plugin/PerformanceOverlayPlugin.d.mts +1 -2
  28. package/dist/builtin-plugin/PerformanceOverlayPlugin.mjs +1 -1
  29. package/dist/index.d.mts +10 -11
  30. package/dist/index.mjs +1 -1
  31. package/dist/{types-CHhzteRO.d.mts → types-Do4sfz9k.d.mts} +147 -48
  32. package/package.json +52 -47
  33. package/dist/ContextMenuPlugin-DDuNDVYG.mjs +0 -1
  34. package/dist/DarkThemePlugin-g_jQnbr2.mjs +0 -1
  35. package/dist/EventMediaPlugin-C10NRApa.mjs +0 -1
  36. package/dist/EventTooltipPlugin-BGMlHyI2.mjs +0 -1
  37. package/dist/LightThemePlugin-CCklHOHQ.mjs +0 -1
  38. package/dist/PerformanceOverlayPlugin-CiGYUAlO.mjs +0 -1
  39. /package/dist/{Logger-CfVK3yFL.mjs → Logger-BTKQPGDj.mjs} +0 -0
  40. /package/dist/{performanceMonitor-BBherdD8.mjs → performanceMonitor-Cb_v1gAo.mjs} +0 -0
  41. /package/dist/{types-Dc2ct_CM.mjs → types-NnKZYB1U.mjs} +0 -0
@@ -74,6 +74,87 @@ interface ContextMenuStyle {
74
74
  borderWidth: number;
75
75
  minWidth: number;
76
76
  }
77
+ type TimelineLocale = "en" | "zh" | "zh-CN";
78
+ type TimelineMessageParams = Record<string, string | number>;
79
+ interface TimelineI18nMessages {
80
+ statusReady: string;
81
+ statusTrackAdded: string;
82
+ statusAtLeastOneTrackRequired: string;
83
+ statusTrackRemoved: string;
84
+ statusEmptyTrackRemoved: string;
85
+ statusEventUpdated: string;
86
+ statusEventDeleted: string;
87
+ statusDataLoaded: string;
88
+ statusTimeIndicatorMoved: string;
89
+ statusZoomChanged: string;
90
+ statusAutoFit: string;
91
+ statusAutoFitCappedWithPadding: string;
92
+ statusAutoFitCappedContentShort: string;
93
+ statusEndTimeUpdated: string;
94
+ statusInvalidSplitPosition: string;
95
+ statusEventSplit: string;
96
+ statusReadOnlyModeEnabled: string;
97
+ statusReadOnlyModeDisabled: string;
98
+ statusEventHighlighted: string;
99
+ statusHighlightCleared: string;
100
+ statusTimelineDestroyed: string;
101
+ statusDragging: string;
102
+ statusAutoTrackAdded: string;
103
+ statusEventPlaced: string;
104
+ statusEventSelected: string;
105
+ statusEventResizing: string;
106
+ statusEventResized: string;
107
+ statusReadOnlyEditDeleteBlocked: string;
108
+ statusReadOnlySplitBlocked: string;
109
+ statusHoverEventTimeRange: string;
110
+ labelTrackName: string;
111
+ labelDurationPrefix: string;
112
+ contextMenuEdit: string;
113
+ contextMenuDelete: string;
114
+ contextMenuExport: string;
115
+ overlayPerformanceMonitor: string;
116
+ overlayFps: string;
117
+ overlayLayerTimesMs: string;
118
+ overlayCollecting: string;
119
+ overlayLayerBackground: string;
120
+ overlayLayerTracks: string;
121
+ overlayLayerTimeline: string;
122
+ overlayLayerGuideLines: string;
123
+ overlayLayerIndicator: string;
124
+ overlayLayerScrollbar: string;
125
+ overlayLayerInteraction: string;
126
+ overlayLayerOverlay: string;
127
+ overlayLayerDragPreview: string;
128
+ errorCanvasNotFound: string;
129
+ errorCanvasContextUnavailable: string;
130
+ errorTimeIndicatorInvalid: string;
131
+ errorZoomLevelInvalid: string;
132
+ errorZoomLevelOutOfRange: string;
133
+ errorEndTimeInvalid: string;
134
+ errorEndTimeNotAfterStart: string;
135
+ warningEventsExceedEndTime: string;
136
+ errorInvalidTrackIndex: string;
137
+ errorInvalidTrackIndexWithValue: string;
138
+ errorInvalidEventIndex: string;
139
+ errorInvalidEventIndexWithValue: string;
140
+ errorInvalidDataFormat: string;
141
+ errorInvalidTimeRange: string;
142
+ errorStartTimeBeforeMin: string;
143
+ errorRenderLayer: string;
144
+ errorCoreLayerHook: string;
145
+ errorPluginDependenciesMissing: string;
146
+ errorPluginLoadFailed: string;
147
+ errorPluginLifecycleFailed: string;
148
+ errorPluginEventFailed: string;
149
+ errorPluginValidationFailed: string;
150
+ warningInvalidDraggingState: string;
151
+ warningDraggingEventMissing: string;
152
+ warningUnknownChangeType: string;
153
+ warningAlreadyInBatchMode: string;
154
+ warningNotInBatchMode: string;
155
+ warningEmptyHtmlTemplateFallback: string;
156
+ warningEmptyTooltipTemplateFallback: string;
157
+ }
77
158
  interface TimelineConfig {
78
159
  canvasHeight?: number;
79
160
  timelineHeight: number;
@@ -97,6 +178,9 @@ interface TimelineConfig {
97
178
  timeIndicatorSnapThreshold: number;
98
179
  timeIndicatorHeadSize: number;
99
180
  timeIndicatorTriangleHeight: number;
181
+ edgeScrollThrottle: number;
182
+ edgeScrollTriggerMargin: number;
183
+ edgeScrollViewportMargin: number;
100
184
  guideLineSnapThreshold: number;
101
185
  enableTimeIndicator: boolean;
102
186
  enableEventResize: boolean;
@@ -110,6 +194,7 @@ interface TimelineConfig {
110
194
  autoRemoveEmptyLastTrack: boolean;
111
195
  readOnly: boolean;
112
196
  showEventDurationLabel: boolean;
197
+ eventDurationPrefix: string;
113
198
  formatEventDuration: ((duration: number) => string) | null;
114
199
  /** 主刻度时间间隔(秒),>0。设置后启用自定义刻度模式 */
115
200
  scale: number | null;
@@ -123,6 +208,8 @@ interface TimelineConfig {
123
208
  contextMenuItems: ContextMenuItem[];
124
209
  contextMenuStyle: ContextMenuStyle;
125
210
  contextMenuHtml?: string | HTMLElement;
211
+ locale: TimelineLocale;
212
+ messages: TimelineI18nMessages;
126
213
  }
127
214
  interface TimelineCallbacks {
128
215
  onEventAdd?: ((data: EventAddData) => void) | null;
@@ -149,7 +236,7 @@ interface TimelineEvent {
149
236
  description: string;
150
237
  color: string;
151
238
  readonly?: boolean;
152
- customData?: Record<string, any>;
239
+ customData?: Record<string, unknown>;
153
240
  media?: {
154
241
  images?: Array<{
155
242
  src: string;
@@ -349,7 +436,7 @@ interface LoadDataFormat {
349
436
  description?: string;
350
437
  color?: string;
351
438
  readonly?: boolean;
352
- customData?: Record<string, any>;
439
+ customData?: Record<string, unknown>;
353
440
  media?: {
354
441
  images?: Array<{
355
442
  src: string;
@@ -368,6 +455,8 @@ interface LoadDataFormat {
368
455
  }
369
456
  interface TimelineOptions {
370
457
  canvasHeight?: number;
458
+ locale?: TimelineLocale;
459
+ messages?: Partial<TimelineI18nMessages>;
371
460
  startTime?: number;
372
461
  endTime?: number;
373
462
  startPaddingTime?: number;
@@ -384,6 +473,9 @@ interface TimelineOptions {
384
473
  snapToSeconds?: boolean;
385
474
  secondPrecisionZoomThreshold?: number;
386
475
  enableTimeIndicator?: boolean;
476
+ edgeScrollThrottle?: number;
477
+ edgeScrollTriggerMargin?: number;
478
+ edgeScrollViewportMargin?: number;
387
479
  enableEventResize?: boolean;
388
480
  enableEventSplit?: boolean;
389
481
  enableContextMenu?: boolean;
@@ -395,6 +487,7 @@ interface TimelineOptions {
395
487
  autoRemoveEmptyLastTrack?: boolean;
396
488
  readOnly?: boolean;
397
489
  showEventDurationLabel?: boolean;
490
+ eventDurationPrefix?: string;
398
491
  formatEventDuration?: (duration: number) => string;
399
492
  /** 主刻度时间间隔(秒),>0。设置后启用自定义刻度模式 */
400
493
  scale?: number;
@@ -430,6 +523,30 @@ declare global {
430
523
  }
431
524
  }
432
525
  //#endregion
526
+ //#region src/utils/time.d.ts
527
+ declare function formatTime(seconds: number, showSeconds?: boolean): string;
528
+ declare function getCurrentTime(): number;
529
+ declare function formatTimeRange(startTime: number, endTime: number): string;
530
+ declare function formatDuration(duration: number, label?: string): string;
531
+ //#endregion
532
+ //#region src/utils/i18n.d.ts
533
+ type TimelineMessageKey = keyof TimelineI18nMessages;
534
+ type ResolvedTimelineLocale = Exclude<TimelineLocale, "zh">;
535
+ declare function normalizeTimelineLocale(locale?: string): ResolvedTimelineLocale;
536
+ declare function createTimelineMessages(locale?: string, overrides?: Partial<TimelineI18nMessages>): TimelineI18nMessages;
537
+ declare function translateTimelineMessage(messages: TimelineI18nMessages, key: TimelineMessageKey, params?: TimelineMessageParams): string;
538
+ declare function translateTimelineConfig(config: Pick<TimelineConfig, "locale" | "messages">, key: TimelineMessageKey, params?: TimelineMessageParams): string;
539
+ declare function createDefaultContextMenuItems(localeOrMessages?: string | TimelineI18nMessages, overrides?: Partial<TimelineI18nMessages>): ContextMenuItem[];
540
+ //#endregion
541
+ //#region src/utils/performanceMonitor.d.ts
542
+ interface PerformanceStats {
543
+ average: number;
544
+ min: number;
545
+ max: number;
546
+ count: number;
547
+ total: number;
548
+ }
549
+ //#endregion
433
550
  //#region src/core/managers/ChangeScheduler.d.ts
434
551
  /**
435
552
  * 状态变更类型
@@ -443,28 +560,29 @@ declare class Timeline {
443
560
  config: TimelineConfig;
444
561
  callbacks: TimelineCallbacks;
445
562
  state: TimelineState;
446
- private mouseHandler;
447
- private wheelHandler;
448
563
  private renderManager;
449
- private guideLinesCache;
450
- private guideLinesCacheTimestamp;
451
- private readonly GUIDE_LINES_CACHE_TTL;
452
- private eventListeners;
564
+ private canvasController;
565
+ private interactionManager;
453
566
  private pluginManager;
567
+ private pluginController;
454
568
  private logger;
455
569
  private errorHandler;
456
570
  private stateManager;
457
571
  private eventIndexManager;
572
+ private eventMutationService;
573
+ private trackManager;
574
+ private timeIndicatorController;
575
+ private viewportController;
576
+ private guideLineService;
577
+ private hitTestService;
458
578
  private changeScheduler;
459
- private currentThemePluginId;
460
579
  constructor(canvasId: string, options?: TimelineOptions);
461
580
  getCanvas(): HTMLCanvasElement;
462
- usePlugin(plugin: any): Promise<boolean>;
463
- getLoadedPlugins(): any[];
581
+ usePlugin(plugin: TimelinePlugin): Promise<boolean>;
582
+ getLoadedPlugins(): TimelinePlugin[];
464
583
  isPluginLoaded(pluginName: string): boolean;
465
584
  removePlugin(pluginId: string): Promise<boolean>;
466
585
  setTheme(theme: "light" | "dark"): Promise<boolean>;
467
- private switchTheme;
468
586
  private init;
469
587
  getContentWidthForZoom(zoomLevel: number): number;
470
588
  hasHorizontalScrollbar(): boolean;
@@ -489,9 +607,7 @@ declare class Timeline {
489
607
  endIndexBatch(): void;
490
608
  invalidateIndexTrack(trackIndex: number): void;
491
609
  invalidateIndexAll(): void;
492
- private autoFitZoomToCanvas;
493
- private setupEventListeners;
494
- private setInitialCanvasSize;
610
+ private autoFitViewport;
495
611
  setCanvasSize(width: number, height: number): void;
496
612
  getCanvasLogicalHeight(): number;
497
613
  getCachedLogicalHeight(): number;
@@ -499,8 +615,7 @@ declare class Timeline {
499
615
  addTrack(): void;
500
616
  removeTrack(): void;
501
617
  autoRemoveEmptyLastTrack(): void;
502
- private validateEventTime;
503
- addEvent(trackIndex: number, startTime: number, endTime: number, title: string, description?: string, customData?: Record<string, any>, readonly?: boolean): void;
618
+ addEvent(trackIndex: number, startTime: number, endTime: number, title: string, description?: string, customData?: Record<string, unknown>, readonly?: boolean): void;
504
619
  updateEvent(trackIndex: number, eventIndex: number, updates: Partial<TimelineEvent>): boolean;
505
620
  updateEventData(trackIndex: number, eventIndex: number, eventData: {
506
621
  title?: string;
@@ -520,25 +635,13 @@ declare class Timeline {
520
635
  * - 使用节流的边界滚动而非每帧滚动
521
636
  */
522
637
  setTimeIndicatorDuringDrag(seconds: number): void;
523
- /** 上一次边界滚动的时间戳 */
524
- private _lastEdgeScrollTime;
525
- /** 边界滚动节流间隔(ms) */
526
- private static readonly EDGE_SCROLL_THROTTLE;
527
- /** 距画布边缘多少 px 内触发滚动 */
528
- private static readonly EDGE_SCROLL_MARGIN;
529
- /**
530
- * 拖拽过程中的节流边界滚动
531
- * 仅当指示器距离画布边缘 < EDGE_SCROLL_MARGIN 时才调整 scrollX,
532
- * 且受 EDGE_SCROLL_THROTTLE 节流。
533
- */
534
- private scrollToTimeIndicatorThrottled;
535
- private scrollToTimeIndicator;
536
638
  zoom(factor: number): void;
537
639
  setZoomLevel(zoomLevel: number): boolean;
538
640
  getZoomLevel(): number;
539
641
  setEndTime(endTime: number): boolean;
540
642
  getEndTime(): number;
541
643
  formatTime(seconds: number): string;
644
+ t(key: TimelineMessageKey, params?: TimelineMessageParams): string;
542
645
  setStatus(text: string): void;
543
646
  getStatus(): string;
544
647
  /**
@@ -583,18 +686,12 @@ declare class Timeline {
583
686
  } | null;
584
687
  isReadOnly(): boolean;
585
688
  destroy(): void;
586
- }
587
- //#endregion
588
- //#region src/utils/performanceMonitor.d.ts
589
- interface PerformanceStats {
590
- average: number;
591
- min: number;
592
- max: number;
593
- count: number;
594
- total: number;
689
+ private clearGuideLineCache;
690
+ private redrawAfterPluginChange;
595
691
  }
596
692
  //#endregion
597
693
  //#region src/plugins/types.d.ts
694
+ type PluginLocalizedText = Partial<Record<TimelineLocale, string>>;
598
695
  declare enum PluginType {
599
696
  RENDER = "render",
600
697
  EVENT_HANDLER = "event_handler",
@@ -613,6 +710,7 @@ interface PluginMetadata {
613
710
  name: string;
614
711
  version: string;
615
712
  description: string;
713
+ descriptionI18n?: PluginLocalizedText;
616
714
  author?: string;
617
715
  type: PluginType;
618
716
  priority?: PluginPriority;
@@ -622,7 +720,7 @@ type RenderLayerPosition = "background" | "overlay";
622
720
  interface RenderLayer {
623
721
  name: string;
624
722
  position: RenderLayerPosition;
625
- render: (ctx: CanvasRenderingContext2D, canvas: HTMLCanvasElement, config: any, state: any) => void;
723
+ render: (ctx: CanvasRenderingContext2D, canvas: HTMLCanvasElement, config: TimelineConfig, state: TimelineState) => void;
626
724
  }
627
725
  /**
628
726
  * 可被插件钩子拦截的核心渲染层
@@ -666,26 +764,27 @@ interface CoreLayerHook {
666
764
  /** 目标核心渲染层 */
667
765
  target: CoreRenderTarget;
668
766
  /** 钩子处理函数 */
669
- handler: (ctx: CanvasRenderingContext2D, canvas: HTMLCanvasElement, config: any, state: any, next: () => void) => void;
767
+ handler: (ctx: CanvasRenderingContext2D, canvas: HTMLCanvasElement, config: TimelineConfig, state: TimelineState, next: () => void) => void;
670
768
  }
769
+ type PluginEventHandler = (...args: unknown[]) => unknown;
671
770
  interface PluginAPI {
672
771
  registerRenderLayer: (layer: RenderLayer) => void;
673
772
  unregisterRenderLayer: (name: string) => void;
674
773
  registerCoreLayerHook: (hook: CoreLayerHook) => void;
675
774
  unregisterCoreLayerHook: (name: string) => void;
676
- registerEventHandler: (event: string, handler: Function) => void;
677
- unregisterEventHandler: (event: string, handler: Function) => void;
775
+ registerEventHandler: (event: string, handler: PluginEventHandler) => void;
776
+ unregisterEventHandler: (event: string, handler: PluginEventHandler) => void;
678
777
  showNotification: (message: string, type?: "info" | "warning" | "error") => void;
679
- getData: (key: string) => any;
680
- setData: (key: string, value: any) => void;
778
+ getData: (key: string) => unknown;
779
+ setData: (key: string, value: unknown) => void;
681
780
  setPerformanceProvider: (provider: PerformanceProvider) => void;
682
781
  getPerformanceStats: () => Map<string, PerformanceStats>;
683
782
  getFPS: () => number;
684
783
  }
685
784
  interface PluginContext {
686
785
  timeline: Timeline;
687
- config: any;
688
- state: any;
786
+ config: TimelineConfig;
787
+ state: TimelineState;
689
788
  api: PluginAPI;
690
789
  }
691
790
  interface TimelinePlugin {
@@ -702,4 +801,4 @@ interface PerformanceProvider {
702
801
  getFPS: () => number;
703
802
  }
704
803
  //#endregion
705
- export { TimelineOptions as A, InteractionTarget as C, TimelineColors as D, TimelineCallbacks as E, Track as M, ZoomData as N, TimelineConfig as O, EventUpdateData as S, TimeIndicatorMoveData as T, EventClickData as _, PluginMetadata as a, EventMoveData as b, RenderLayer as c, Timeline as d, ChangeType as f, EventAddData as g, ContextMenuStyle as h, PluginContext as i, TimelineState as j, TimelineEvent as k, RenderLayerPosition as l, ContextMenuItem as m, CoreRenderTarget as n, PluginPriority as o, ContextMenuData as p, PluginAPI as r, PluginType as s, CoreLayerHook as t, TimelinePlugin as u, EventDeleteData as v, LoadDataFormat as w, EventTextStyle as x, EventEditData as y };
804
+ export { EventMoveData as A, TimelineI18nMessages as B, ContextMenuData as C, EventClickData as D, EventAddData as E, TimeIndicatorMoveData as F, Track as G, TimelineMessageParams as H, TimelineCallbacks as I, ZoomData as K, TimelineColors as L, EventUpdateData as M, InteractionTarget as N, EventDeleteData as O, LoadDataFormat as P, TimelineConfig as R, getCurrentTime as S, ContextMenuStyle as T, TimelineOptions as U, TimelineLocale as V, TimelineState as W, translateTimelineConfig as _, PluginLocalizedText as a, formatTime as b, PluginType as c, TimelinePlugin as d, Timeline as f, normalizeTimelineLocale as g, createTimelineMessages as h, PluginContext as i, EventTextStyle as j, EventEditData as k, RenderLayer as l, createDefaultContextMenuItems as m, CoreRenderTarget as n, PluginMetadata as o, ChangeType as p, PluginAPI as r, PluginPriority as s, CoreLayerHook as t, RenderLayerPosition as u, translateTimelineMessage as v, ContextMenuItem as w, formatTimeRange as x, formatDuration as y, TimelineEvent as z };
package/package.json CHANGED
@@ -1,48 +1,53 @@
1
- {
2
- "name": "timeline-canvas",
3
- "version": "1.3.1",
4
- "description": "A powerful timeline component built with Canvas and TypeScript",
5
- "main": "dist/index.mjs",
6
- "module": "dist/index.mjs",
7
- "types": "dist/index.d.mts",
8
- "type": "module",
9
- "scripts": {
10
- "build": "tsdown",
11
- "dev": "tsdown --watch",
12
- "typecheck": "tsc -p tsconfig.json --noEmit",
13
- "lint": "oxlint src",
14
- "test": "echo \"Error: no test specified\" && exit 1"
15
- },
16
- "keywords": [
17
- "timeline",
18
- "canvas",
19
- "typescript",
20
- "event-timeline",
21
- "visual-timeline"
22
- ],
23
- "author": "sky <https://github.com/umbrella22>",
24
- "license": "MIT",
25
- "packageManager": "pnpm@10.18.1",
26
- "devDependencies": {
27
- "@types/node": "^24.10.1",
28
- "oxlint": "^1.43.0"
29
- },
30
- "dependencies": {
31
- "immer": "^10.1.1"
32
- },
33
- "files": [
34
- "dist",
35
- "README.md",
36
- "README_CN.md"
37
- ],
38
- "exports": {
39
- ".": {
40
- "types": "./dist/index.d.mts",
41
- "import": "./dist/index.mjs"
42
- },
43
- "./builtin-plugin/*": {
44
- "types": "./dist/builtin-plugin/*.d.mts",
45
- "import": "./dist/builtin-plugin/*.mjs"
46
- }
47
- }
1
+ {
2
+ "name": "timeline-canvas",
3
+ "version": "1.4.1",
4
+ "description": "A powerful timeline component built with Canvas and TypeScript",
5
+ "main": "dist/index.mjs",
6
+ "module": "dist/index.mjs",
7
+ "types": "dist/index.d.mts",
8
+ "type": "module",
9
+ "scripts": {
10
+ "build": "tsdown",
11
+ "dev": "tsdown --watch",
12
+ "typecheck": "tsc -p tsconfig.json --noEmit",
13
+ "lint": "oxlint src tests vitest.config.ts",
14
+ "test": "vitest",
15
+ "test:run": "vitest run",
16
+ "test:coverage": "vitest run --coverage"
17
+ },
18
+ "keywords": [
19
+ "timeline",
20
+ "canvas",
21
+ "typescript",
22
+ "event-timeline",
23
+ "visual-timeline"
24
+ ],
25
+ "author": "sky <https://github.com/umbrella22>",
26
+ "license": "MIT",
27
+ "packageManager": "pnpm@10.18.1",
28
+ "devDependencies": {
29
+ "@types/node": "^24.10.1",
30
+ "@vitest/coverage-v8": "^4.1.2",
31
+ "jsdom": "^29.0.1",
32
+ "oxlint": "^1.43.0",
33
+ "vitest": "^4.1.2"
34
+ },
35
+ "dependencies": {
36
+ "immer": "^10.1.1"
37
+ },
38
+ "files": [
39
+ "dist",
40
+ "README.md",
41
+ "README_CN.md"
42
+ ],
43
+ "exports": {
44
+ ".": {
45
+ "types": "./dist/index.d.mts",
46
+ "import": "./dist/index.mjs"
47
+ },
48
+ "./builtin-plugin/*": {
49
+ "types": "./dist/builtin-plugin/*.d.mts",
50
+ "import": "./dist/builtin-plugin/*.mjs"
51
+ }
52
+ }
48
53
  }
@@ -1 +0,0 @@
1
- import{i as e}from"./Logger-CfVK3yFL.mjs";import{n as t}from"./types-Dc2ct_CM.mjs";const n=e(`ContextMenuPlugin`);function r(e={}){return{metadata:{name:`context-menu`,version:`1.0.0`,description:`Context menu as plugin, supports HTML takeover`,type:t.EXTENSION},activate(t){let r=t.config&&t.config.contextMenuHtml||void 0,i=e.htmlTemplate||(typeof r==`string`?r:void 0),a=!!i;a&&(!i||i.trim()===``)&&(n.warn(`htmlTemplate is empty, falling back to Canvas rendering`),a=!1),t.api.registerRenderLayer({name:`context-menu-overlay`,position:`overlay`,render(e,n,r,o){if(!r.enableContextMenu||!o.contextMenuVisible||!o.contextMenuEvent){let e=t.api.getData(`contextMenuContainer`)||null;e&&(e.style.display=`none`),o.contextMenuBounds=null;return}let{padding:s,itemHeight:c,borderRadius:l,borderWidth:u,minWidth:d,fontSize:f,fontFamily:p,fontWeight:m}=r.contextMenuStyle;e.save(),e.font=`${m} ${f}px ${p}`;let h=d,g=`${m}-${f}-${p}`,_=t.api.getData(`contextMenuTextWidthCache`)||{},v=_[g]||{};for(let t of r.contextMenuItems){let n=v[t.name],r=n===void 0?e.measureText(t.name).width:n;n===void 0&&(v[t.name]=r),h=Math.max(h,r+s*2)}_[g]=v,t.api.setData(`contextMenuTextWidthCache`,_);let y=h,b=r.contextMenuItems.length*c+s*2,x=t.timeline.getCanvas().getBoundingClientRect(),S=o.contextMenuX,C=o.contextMenuY;if(S+y>x.width&&(S=x.width-y-5),C+b>x.height&&(C=x.height-b-5),o.contextMenuBounds={x:S,y:C,width:y,height:b,itemHeight:c,padding:s},a){let n=t.api.getData(`contextMenuContainer`)||null;if(!n){n=document.createElement(`div`),n.style.position=`absolute`,n.style.zIndex=`1000`,n.style.boxShadow=`0 2px 10px rgba(0,0,0,0.3)`,n.style.border=`${u}px solid ${r.colors.contextMenuBorder}`,n.style.borderRadius=`${l}px`,n.style.font=`${m} ${f}px ${p}`,n.style.background=r.colors.contextMenuBackground,n.style.color=r.colors.contextMenuText;let e=t.timeline.getCanvas().parentElement||document.body;e.style.position=e.style.position||`relative`,e.appendChild(n),t.api.setData(`contextMenuContainer`,n)}if(n.style.display=`block`,n.style.left=`${S}px`,n.style.top=`${C}px`,n.style.width=`${y}px`,n.style.height=`${b}px`,i)n.innerHTML=i;else{let e=``;for(let t=0;t<r.contextMenuItems.length;t++){let n=r.contextMenuItems[t],i=o.hoveredContextMenuItem===t,a=i?r.colors.contextMenuHoverBackground:`transparent`,l=i?r.colors.contextMenuHoverText:r.colors.contextMenuText;e+=`<div style="height:${c}px; padding:${s}px; background:${a}; color:${l}; display:flex; align-items:center;">${n.name}</div>`}n.innerHTML=e}e.restore();return}e.shadowColor=`rgba(0, 0, 0, 0.3)`,e.shadowBlur=10,e.shadowOffsetX=0,e.shadowOffsetY=2,e.fillStyle=r.colors.contextMenuBackground,e.beginPath(),e.roundRect?e.roundRect(S,C,y,b,l):(e.moveTo(S+l,C),e.lineTo(S+y-l,C),e.quadraticCurveTo(S+y,C,S+y,C+l),e.lineTo(S+y,C+b-l),e.quadraticCurveTo(S+y,C+b,S+y-l,C+b),e.lineTo(S+l,C+b),e.quadraticCurveTo(S,C+b,S,C+b-l),e.lineTo(S,C+l),e.quadraticCurveTo(S,C,S+l,C)),e.fill(),e.shadowColor=`transparent`,e.strokeStyle=r.colors.contextMenuBorder,e.lineWidth=u,e.stroke(),e.font=`${m} ${f}px ${p}`;for(let t=0;t<r.contextMenuItems.length;t++){let n=r.contextMenuItems[t],i=C+s+t*c;o.hoveredContextMenuItem===t&&(e.fillStyle=r.colors.contextMenuHoverBackground,e.beginPath(),t===0?e.roundRect?e.roundRect(S+u,i,y-u*2,c,[l-u,l-u,0,0]):e.fillRect(S+u,i,y-u*2,c):t===r.contextMenuItems.length-1&&e.roundRect?e.roundRect(S+u,i,y-u*2,c,[0,0,l-u,l-u]):e.fillRect(S+u,i,y-u*2,c),e.fill()),e.fillStyle=o.hoveredContextMenuItem===t?r.colors.contextMenuHoverText:r.colors.contextMenuText,e.textAlign=`left`,e.textBaseline=`middle`,e.fillText(n.name,S+s,i+c/2)}e.restore()}})},deactivate(e){e.api.unregisterRenderLayer(`context-menu-overlay`);let t=e.api.getData(`contextMenuContainer`)||null;t&&t.parentElement&&t.parentElement.removeChild(t)},destroy(e){let t=e.api.getData(`contextMenuContainer`)||null;t&&t.parentElement&&t.parentElement.removeChild(t)}}}export{r as t};
@@ -1 +0,0 @@
1
- import{n as e}from"./types-Dc2ct_CM.mjs";const t={canvasBackground:`#1E1E2E`,timelineBackground:`#2D2D3D`,trackBackground:`#2A2A3A`,trackBackgroundSelected:`#3A3A4A`,timelineText:`#CCCCDD`,timelineGrid:`#5A5A7A`,timelineSubGrid:`#3A3A4A`,trackText:`#CCCCDD`,eventColors:[`#FF6B6B`,`#4ECDC4`,`#45B7D1`,`#96CEB4`,`#FECA57`,`#FF9FF3`],eventText:`#FFFFFF`,eventBorder:`#FFFFFF`,eventBorderSelected:`#FFD700`,eventOverlay:`rgba(255, 255, 255, 0.2)`,dragPreviewValid:`rgba(100, 255, 100, 0.5)`,dragPreviewInvalid:`rgba(255, 100, 100, 0.5)`,dragPreviewBorderValid:`#00FF00`,dragPreviewBorderInvalid:`#FF0000`,timeIndicator:`#FF6B6B`,guideLine:`#00D9FF`,guideLineLabel:`#00D9FF`,dragTimeReferenceLine:`#FFD700`,dragTimeReferenceLabel:`#FFD700`,dragTimeReferenceLabelBackground:`rgba(0, 0, 0, 0)`,scrollbarTrack:`rgba(255, 255, 255, 0.6)`,scrollbarHandle:`rgba(150, 150, 150, 0.8)`,scrollbarHandleHover:`rgba(0, 0, 0, 0.85)`,scrollbarHandleHighlight:`rgba(255, 255, 255, 0.3)`,scrollbarBorder:`rgba(255, 255, 255, 0.9)`,contextMenuBackground:`#2D2D3D`,contextMenuBorder:`#5A5A7A`,contextMenuText:`#CCCCDD`,contextMenuHoverBackground:`#3A3A4A`,contextMenuHoverText:`#FFFFFF`,eventDurationLabel:`#FFD700`},n={metadata:{name:`theme-dark`,version:`1.0.0`,description:`Dark theme for timeline`,type:e.THEME},activate(e){e.config.colors={...e.config.colors,...t},e.api.registerRenderLayer({name:`theme-dark-background`,position:`background`,render(e,t,n){e.fillStyle=n.colors.canvasBackground,e.fillRect(0,0,t.width,t.height)}})},deactivate(e){e.api.unregisterRenderLayer(`theme-dark-background`)}};export{n as t};
@@ -1 +0,0 @@
1
- import{n as e}from"./types-Dc2ct_CM.mjs";function t(e,t=!0){let n=Math.round(e),r=Math.floor(n/3600),i=Math.floor(n%3600/60),a=n%60;return t?`${r.toString().padStart(2,`0`)}:${i.toString().padStart(2,`0`)}:${a.toString().padStart(2,`0`)}`:`${r.toString().padStart(2,`0`)}:${i.toString().padStart(2,`0`)}`}function n(){let e=new Date;return e.getHours()*3600+e.getMinutes()*60+e.getSeconds()}function r(e,t,n,r,i,a){if(i!=null&&i>0){let t=i/Math.max(1,Math.floor(a??10));return e>=r?t:i}return!n||e<r?t*60:[{threshold:10,seconds:.5},{threshold:8,seconds:1},{threshold:5,seconds:2},{threshold:3,seconds:5},{threshold:2,seconds:10},{threshold:1.5,seconds:15},{threshold:0,seconds:30}].find(t=>e>=t.threshold)?.seconds??30}function i(e,t){return Math.round(e/t)*t}function a(e,t=3){let n=10**t;return Math.round(e*n)/n}function o(e,n){return`${t(e)} - ${t(n)}`}function s(e){return`持续 ${t(a(e))}`}function c(e,t,n,r,i,a,o=!1){e.beginPath(),e.moveTo(t+a,n),e.lineTo(t+r-a,n),e.arcTo(t+r,n,t+r,n+a,a),e.lineTo(t+r,n+i-a),e.arcTo(t+r,n+i,t+r-a,n+i,a),e.lineTo(t+a,n+i),e.arcTo(t,n+i,t,n+i-a,a),e.lineTo(t,n+a),e.arcTo(t,n,t+a,n,a),e.closePath(),o?e.stroke():e.fill()}function l(e,t,n,r,i,a){return n+(e-t)*r*i-a}const u={canvasBackground:`#1E1E2E`,timelineBackground:`#2D2D3D`,trackBackground:`#2A2A3A`,trackBackgroundSelected:`#3A3A4A`,timelineText:`#CCCCDD`,timelineGrid:`#5A5A7A`,timelineSubGrid:`#3A3A4A`,trackText:`#CCCCDD`,eventColors:[`#FF6B6B`,`#4ECDC4`,`#45B7D1`,`#96CEB4`,`#FECA57`,`#FF9FF3`],eventText:`#FFFFFF`,eventBorder:`#FFFFFF`,eventBorderSelected:`#FFD700`,eventOverlay:`rgba(255, 255, 255, 0.2)`,dragPreviewValid:`rgba(100, 255, 100, 0.5)`,dragPreviewInvalid:`rgba(255, 100, 100, 0.5)`,dragPreviewBorderValid:`#00FF00`,dragPreviewBorderInvalid:`#FF0000`,timeIndicator:`#FF6B6B`,guideLine:`#00D9FF`,guideLineLabel:`#00D9FF`,dragTimeReferenceLine:`#FFD700`,dragTimeReferenceLabel:`#FFD700`,dragTimeReferenceLabelBackground:`rgba(0, 0, 0, 0)`,scrollbarTrack:`rgba(255, 255, 255, 0.6)`,scrollbarHandle:`rgba(150, 150, 150, 0.8)`,scrollbarHandleHover:`rgba(0, 0, 0, 0.85)`,scrollbarHandleHighlight:`rgba(255, 255, 255, 0.3)`,scrollbarBorder:`rgba(255, 255, 255, 0.9)`,contextMenuBackground:`#2D2D3D`,contextMenuBorder:`#5A5A7A`,contextMenuText:`#CCCCDD`,contextMenuHoverBackground:`#3A3A4A`,contextMenuHoverText:`#FFFFFF`,eventDurationLabel:`#FFD700`},d={titleFontSize:`auto`,timeFontSize:`auto`,titleFontFamily:`Arial`,timeFontFamily:`Arial`,titleFontWeight:`bold`,timeFontWeight:`normal`,titleColor:null,timeColor:null,textAlign:`left`,verticalAlign:`middle`,titleOffsetY:0,timeOffsetY:0,showTitle:!0,showTime:!0,minHeightForTitle:40,minHeightForTime:50},f={borderRadius:2,enableSelectionGlow:!1,selectionGlowBlur:10},p=[{type:`edit`,name:`编辑`},{type:`delete`,name:`删除`},{type:`export`,name:`导出`}],m={fontSize:14,fontFamily:`Arial, sans-serif`,fontWeight:`normal`,padding:8,itemHeight:32,borderRadius:6,borderWidth:1,minWidth:120},h={timelineHeight:40,trackHeight:80,trackMargin:10,firstTrackTopMargin:10,secondWidth:100/3600,startTime:0,endTime:86400,startPaddingTime:.5,endPaddingTime:0,autoFitOnInit:!0,minAutoFitZoom:1,maxAutoFitZoom:3,timeUnit:`second`,timeFormat:`24h`,snapInterval:15,snapToSeconds:!0,secondPrecisionZoomThreshold:1.5,timeIndicatorWidth:3,timeIndicatorSnapThreshold:10,timeIndicatorHeadSize:12,timeIndicatorTriangleHeight:8,guideLineSnapThreshold:1,enableTimeIndicator:!0,enableEventResize:!0,enableEventSplit:!0,enableContextMenu:!0,resizeHandleWidth:8,minEventDuration:.25,debug:!1,enablePerformanceMonitor:!1,autoAddTrack:!0,autoRemoveEmptyLastTrack:!0,readOnly:!1,showEventDurationLabel:!0,formatEventDuration:null,scale:null,scaleSplitCount:10,getScaleRender:null};function g(e){return{id:e.id,startTime:e.startTime,endTime:e.endTime,duration:e.duration,title:e.title,description:e.description,color:e.color,...e.readonly?{readonly:e.readonly}:{},...e.customData?{customData:{...e.customData}}:{}}}const _=new Map,v=new Map;function y(e,t,n,r){let i=_.get(e);if(i)return i;let a=new Path2D,o=r/2,s=Math.max(1,Math.floor((r-2)/2)),c=t.length,l=Math.max(1,n-1);for(let e=0;e<n;e++){let n=Math.min(c-1,Math.max(0,Math.floor(e/l*c))),r=Math.max(-1,Math.min(1,t[n]))*s;a.moveTo(e,o-r),a.lineTo(e,o+r)}return _.set(e,a),a}function b(e,t,n,r,i,a){let o=v.get(e);if(o&&o.width===n&&o.height===r)return o.bitmap;if(typeof OffscreenCanvas>`u`||n<=0||r<=0)return null;try{let o=Math.max(1,Math.ceil(n)),s=Math.max(1,Math.ceil(r)),c=new OffscreenCanvas(o,s),l=c.getContext(`2d`);if(!l)return null;a&&(l.fillStyle=a,l.fillRect(0,0,o,s));let u=y(`${e}_path`,t,o,s);l.strokeStyle=i,l.lineWidth=1,l.stroke(u);let d=c.transferToImageBitmap(),f=v.get(e);return f&&f.bitmap.close(),v.set(e,{bitmap:d,width:o,height:s}),d}catch{return null}}function x(){return{metadata:{name:`event-media`,version:`1.0.0`,description:`Render images and waveforms inside event blocks`,type:e.RENDER},async activate(e){let t=new Map,n=new Map,r=new Map;e.api.setData(`eventMediaImageCache`,t),e.api.setData(`eventMediaImageLoading`,n),e.api.setData(`eventMediaWaveCache`,r);let i=(t,n,r,i,a,o,s,l,u,d)=>{let f=e.api.getData(`eventMediaImageCache`),p=e.api.getData(`eventMediaImageLoading`),m=e.api.getData(`eventMediaWaveCache`),h=r.tracks[i].events[a],g=s+u,_=n.eventBlockStyle.borderRadius;t.save(),_>0?(c(t,o,g,l,d,_),t.clip()):(t.beginPath(),t.rect(o,g,l,d),t.clip());let v=h.media&&h.media.images||[];if(v.length>0&&f&&p)for(let e of v){let n=`${h.id??`${i}_${a}`}_${e.src}`,r=f.get(n);if(!r&&!p.get(n)){let t=fetch(e.src).then(e=>e.blob()).then(e=>createImageBitmap(e)).then(e=>(f.set(n,e),e)).catch(()=>void 0);p.set(n,t)}if(r=f.get(n),r){let n=e.fit||`cover`,i=e.opacity===void 0?.35:e.opacity,a=l,s=d;if(n!==`stretch`){let e=r.width,t=r.height,i=n===`cover`?Math.max(l/e,d/t):Math.min(l/e,d/t);a=Math.max(1,Math.floor(e*i)),s=Math.max(1,Math.floor(t*i))}let c=o+(l-a)/2,u=g+(d-s)/2,f=t.globalAlpha;t.globalAlpha=i,t.drawImage(r,0,0,r.width,r.height,c,u,a,s),t.globalAlpha=f}}let x=h.media&&h.media.waveform||void 0;if(x){let e=`${h.id??`${i}_${a}`}_wf`,n=m?m.get(e):void 0;if(!n){let t=x.data;n=Array.isArray(t)?new Float32Array(t):t,m&&m.set(e,n)}let r=x.opacity===void 0?.5:x.opacity,s=t.globalAlpha;t.globalAlpha=r;let c=x.color||`#00A0FF`,u=Math.max(1,Math.ceil(l)),f=Math.max(1,Math.ceil(d)),p=b(`${e}_${u}_${f}_${c}_${x.backgroundColor||``}`,n,u,f,c,x.backgroundColor);if(p)t.drawImage(p,o,g,l,d);else{x.backgroundColor&&(t.fillStyle=x.backgroundColor,t.fillRect(o,g,l,d));let r=y(`${e}_${u}_${f}`,n,u,f);t.save(),t.translate(o,g),t.strokeStyle=c,t.lineWidth=1,t.stroke(r),t.restore()}t.globalAlpha=s}t.restore()};e.api.registerEventHandler(`render:event:media`,i),e.api.setData(`eventMediaHandler`,i)},deactivate(e){let t=e.api.getData(`eventMediaHandler`);t&&e.api.unregisterEventHandler(`render:event:media`,t);let n=e.api.getData(`eventMediaImageCache`);n&&n.clear();let r=e.api.getData(`eventMediaImageLoading`);r&&r.clear();let i=e.api.getData(`eventMediaWaveCache`);i&&i.clear();for(let e of v.values())e.bitmap.close();v.clear(),_.clear()}}}export{i as _,p as a,d as c,a as d,s as f,r as g,n as h,h as i,c as l,o as m,g as n,m as o,t as p,u as r,f as s,x as t,l as u};
@@ -1 +0,0 @@
1
- import{i as e}from"./Logger-CfVK3yFL.mjs";import{n as t}from"./types-Dc2ct_CM.mjs";const n=e(`EventTooltipPlugin`);function r(e={}){let{htmlTemplate:r,showDelay:i=300,maxWidth:a=300,padding:o=8,borderRadius:s=4,backgroundColor:c=`#333`,textColor:l=`#fff`,borderColor:u=`#555`,fontSize:d=12,fontFamily:f=`Arial, sans-serif`}=e,p={visible:!1,title:``,x:0,y:0,trackIndex:-1,eventIndex:-1},m=null,h=null;function g(e,t,n){return e.measureText(t).width>n}return{metadata:{name:`event-tooltip`,version:`1.0.0`,description:`Tooltip plugin for displaying full event title when text is truncated`,type:t.EXTENSION},activate(e){let t=e.timeline.getCanvas(),_=!1,v=null,y=n=>{let r=t.getBoundingClientRect(),a=n.clientX-r.left,o=n.clientY-r.top,s=e.config,c=e.state,l=e.timeline.getEventAtPosition(a,o);if(l){let{trackIndex:n,eventIndex:r}=l,u=c.tracks[n]?.events[r];if(!u){x();return}if(h&&h.trackIndex===n&&h.eventIndex===r&&p.visible){p.x=a,p.y=o,e.timeline.draw();return}h={trackIndex:n,eventIndex:r},m&&=(clearTimeout(m),null);let d=u.duration*s.secondWidth*c.zoomLevel-20,f=t.getContext(`2d`);if(!f)return;let _=s.eventTextStyle,v=_.titleFontSize===`auto`?Math.max(10,Math.min(14,s.trackHeight*.175)):_.titleFontSize;f.font=`${_.titleFontWeight} ${v}px ${_.titleFontFamily}`,g(f,u.title,d)?m=setTimeout(()=>{p={visible:!0,title:u.title,x:a,y:o,trackIndex:n,eventIndex:r},e.timeline.draw()},i):x()}else x()},b=e=>{v=e,_||(_=!0,requestAnimationFrame(()=>{_=!1,v&&=(y(v),null)}))},x=()=>{m&&=(clearTimeout(m),null),h=null,p.visible&&(p.visible=!1,e.timeline.draw())},S=()=>{x()};t.addEventListener(`mousemove`,b),t.addEventListener(`mouseleave`,S),e.api.setData(`tooltipMouseMoveHandler`,b),e.api.setData(`tooltipMouseLeaveHandler`,S),e.api.registerRenderLayer({name:`event-tooltip-overlay`,position:`overlay`,render(t,i,m,h){if(!p.visible||!p.title){let t=e.api.getData(`tooltipContainer`)||null;t&&(t.style.display=`none`);return}let g=e.timeline.getCanvas().getBoundingClientRect(),_=p.x,v=p.y-10;t.save(),t.font=`${d}px ${f}`;let y=p.title.split(``),b=[],x=``;for(let e of y){let n=x+e;t.measureText(n).width>a-o*2?x?(b.push(x),x=e):b.push(e):x=n}x&&b.push(x);let S=0;for(let e of b){let n=t.measureText(e).width;S=Math.max(S,n)}S=Math.min(S+o*2,a);let C=d*1.4,w=b.length*C+o*2;if(v-=w,_+S>g.width&&(_=g.width-S-5),_<5&&(_=5),v<5&&(v=p.y+20),r){let i=r(p.title);if(!i||i.trim()===``)n.warn(`htmlTemplate returned empty content, falling back to Canvas rendering`);else{let n=e.api.getData(`tooltipContainer`)||null;if(!n){n=document.createElement(`div`),n.style.position=`absolute`,n.style.zIndex=`1001`,n.style.pointerEvents=`none`,n.style.boxShadow=`0 2px 8px rgba(0,0,0,0.3)`,n.style.border=`1px solid ${u}`,n.style.borderRadius=`${s}px`,n.style.padding=`${o}px`,n.style.fontSize=`${d}px`,n.style.fontFamily=f,n.style.backgroundColor=c,n.style.color=l,n.style.maxWidth=`${a}px`,n.style.wordWrap=`break-word`,n.style.whiteSpace=`pre-wrap`;let t=e.timeline.getCanvas().parentElement||document.body;t.style.position=t.style.position||`relative`,t.appendChild(n),e.api.setData(`tooltipContainer`,n)}n.style.display=`block`,n.style.left=`${_}px`,n.style.top=`${v}px`,n.innerHTML=i,t.restore();return}}if(t.shadowColor=`rgba(0, 0, 0, 0.3)`,t.shadowBlur=8,t.shadowOffsetX=0,t.shadowOffsetY=2,t.fillStyle=c,t.beginPath(),t.roundRect)t.roundRect(_,v,S,w,s);else{let e=_,n=v,r=S,i=w,a=s;t.moveTo(e+a,n),t.lineTo(e+r-a,n),t.quadraticCurveTo(e+r,n,e+r,n+a),t.lineTo(e+r,n+i-a),t.quadraticCurveTo(e+r,n+i,e+r-a,n+i),t.lineTo(e+a,n+i),t.quadraticCurveTo(e,n+i,e,n+i-a),t.lineTo(e,n+a),t.quadraticCurveTo(e,n,e+a,n)}t.fill(),t.shadowColor=`transparent`,t.shadowBlur=0,t.strokeStyle=u,t.lineWidth=1,t.stroke(),t.fillStyle=l,t.font=`${d}px ${f}`,t.textAlign=`left`,t.textBaseline=`top`;for(let e=0;e<b.length;e++)t.fillText(b[e],_+o,v+o+e*C);t.restore()}})},deactivate(e){let t=e.timeline.getCanvas(),n=e.api.getData(`tooltipMouseMoveHandler`),r=e.api.getData(`tooltipMouseLeaveHandler`);n&&t.removeEventListener(`mousemove`,n),r&&t.removeEventListener(`mouseleave`,r),m&&=(clearTimeout(m),null),e.api.unregisterRenderLayer(`event-tooltip-overlay`);let i=e.api.getData(`tooltipContainer`)||null;i&&i.parentElement&&i.parentElement.removeChild(i)},destroy(e){let t=e.api.getData(`tooltipContainer`)||null;t&&t.parentElement&&t.parentElement.removeChild(t),m&&=(clearTimeout(m),null)}}}export{r as t};
@@ -1 +0,0 @@
1
- import{n as e}from"./types-Dc2ct_CM.mjs";const t={canvasBackground:`#FFFFFF`,timelineBackground:`#FFFFFF`,trackBackground:`#FFFFFF`,trackBackgroundSelected:`rgba(63, 118, 252, 0.1)`,trackBackgroundOdd:`#FFFFFF`,trackBackgroundEven:`#F9FAFD`,timelineText:`#969BA5`,timelineGrid:`#E5E5E5`,timelineSubGrid:`#fff`,trackText:`#CCCCDD`,eventColors:[`rgba(63, 118, 252, 0.16)`],eventText:`#FFFFFF`,eventBorder:`#FFFFFF`,eventBorderSelected:`#3F76FC`,eventOverlay:`rgba(255, 255, 255, 0.2)`,dragPreviewValid:`rgba(100, 255, 100, 0.5)`,dragPreviewInvalid:`rgba(255, 100, 100, 0.5)`,dragPreviewBorderValid:`#00FF00`,dragPreviewBorderInvalid:`#FF0000`,timeIndicator:`#3F76FC`,guideLine:`#00D9FF`,guideLineLabel:`#00D9FF`,dragTimeReferenceLine:`#FFD700`,dragTimeReferenceLabel:`#FFD700`,dragTimeReferenceLabelBackground:`rgba(0, 0, 0, 0)`,scrollbarTrack:`rgba(63, 118, 252, 0.08)`,scrollbarHandle:`rgba(63, 118, 252, 0.5)`,scrollbarHandleHover:`rgba(63, 118, 252, 0.8)`,scrollbarHandleHighlight:`rgba(63, 118, 252, 0.12)`,scrollbarBorder:`rgba(63, 118, 252, 0.6)`,contextMenuBackground:`#2D2D3D`,contextMenuBorder:`#5A5A7A`,contextMenuText:`#CCCCDD`,contextMenuHoverBackground:`#4a00e0`,contextMenuHoverText:`#FFFFFF`,eventDurationLabel:`#3F76FC`},n={metadata:{name:`theme-light`,version:`1.0.0`,description:`Light theme for timeline`,type:e.THEME},activate(e){e.config.colors={...e.config.colors,...t},e.api.registerRenderLayer({name:`theme-light-background`,position:`background`,render(e,t,n){e.fillStyle=n.colors.canvasBackground,e.fillRect(0,0,t.width,t.height)}})},deactivate(e){e.api.unregisterRenderLayer(`theme-light-background`)}};export{n as t};
@@ -1 +0,0 @@
1
- import{t as e}from"./performanceMonitor-BBherdD8.mjs";import{n as t}from"./types-Dc2ct_CM.mjs";const n={metadata:{name:`performance-overlay`,version:`1.0.0`,description:`Draw performance metrics overlay`,type:t.TOOL},activate(t){let n=new e(t.config.enablePerformanceMonitor||t.config.debug);t.api.setPerformanceProvider(n),t.api.setData(`perfMonitor`,n),t.api.setData(`perfOverlayPos`,{x:10,y:10}),t.api.setData(`perfOverlayDragging`,!1),t.api.setData(`perfOverlayOffset`,{x:0,y:0});let r=t.timeline.getCanvas(),i=e=>{let n=r.getBoundingClientRect(),i=e.clientX-n.left,a=e.clientY-n.top,o=t.api.getData(`perfOverlaySize`),s=t.api.getData(`perfOverlayPos`)||{x:10,y:10};o&&i>=s.x&&i<=s.x+o.width&&a>=s.y&&a<=s.y+o.height&&(t.api.setData(`perfOverlayDragging`,!0),t.api.setData(`perfOverlayOffset`,{x:i-s.x,y:a-s.y}),e.stopImmediatePropagation(),e.preventDefault())},a=e=>{if(!t.api.getData(`perfOverlayDragging`))return;let n=r.getBoundingClientRect(),i=e.clientX-n.left,a=e.clientY-n.top,o=t.api.getData(`perfOverlayOffset`)||{x:0,y:0},s=t.api.getData(`perfOverlaySize`)||{width:0,height:0},c=i-o.x,l=a-o.y;c=Math.max(0,Math.min(n.width-s.width,c)),l=Math.max(0,Math.min(n.height-s.height,l)),t.api.setData(`perfOverlayPos`,{x:c,y:l}),t.timeline.markDirty([`overlay`]),t.timeline.draw(),e.stopImmediatePropagation(),e.preventDefault()},o=e=>{t.api.getData(`perfOverlayDragging`)&&t.api.setData(`perfOverlayDragging`,!1)};r.addEventListener(`mousedown`,i,{capture:!0}),r.addEventListener(`mousemove`,a,{capture:!0}),window.addEventListener(`mouseup`,o,{capture:!0}),t.api.setData(`perfOverlayListeners`,{onMouseDown:i,onMouseMove:a,onMouseUp:o}),t.api.registerRenderLayer({name:`performance-overlay`,position:`overlay`,render(e){let n=t.api.getData(`perfMonitor`),r=!!(t.config.enablePerformanceMonitor||t.config.debug);if(n)if(r)n.enable();else{n.disable(),n.clear();return}else if(!r)return;let i=t.api.getPerformanceStats(),a=t.api.getFPS(),o=Array.from(i.entries()),s=[`background`,`tracks`,`timeline`,`interaction`,`guideLines`,`scrollbar`,`overlay`,`dragPreview`],c=t.timeline.getLastLayerTimes?t.timeline.getLastLayerTimes():void 0,l=c?s.filter(e=>c[e]!==void 0).length:0,u=c?1+l:0,d=25+(1+(i.size===0?1:o.length)+u)*20+30,f=t.api.getData(`perfOverlayPos`)||{x:10,y:10};t.api.setData(`perfOverlaySize`,{width:280,height:d}),e.fillStyle=`rgba(0, 0, 0, 0.8)`,e.fillRect(f.x,f.y,280,d),e.strokeStyle=`rgba(100, 255, 100, 0.6)`,e.lineWidth=2,e.strokeRect(f.x,f.y,280,d),e.fillStyle=`#00FF00`,e.font=`bold 16px monospace`,e.textAlign=`left`,e.fillText(`性能监控报告`,f.x+10,f.y+20);let p=f.y+20+25;if(e.fillStyle=a>=55?`#00FF00`:a>=30?`#FFFF00`:`#FF0000`,e.font=`bold 14px monospace`,e.fillText(`FPS: ${a.toFixed(1)}`,f.x+10,p),e.font=`12px monospace`,p+=20,c){e.fillStyle=`#00FFFF`,e.font=`bold 12px monospace`,e.fillText(`Layer Times (ms):`,f.x+10,p),p+=20,e.font=`12px monospace`,e.fillStyle=`#FFFFFF`;for(let t of s)c[t]!==void 0&&(e.fillText(`${t}: ${c[t].toFixed(2)}`,f.x+10,p),p+=20)}i.size===0?(e.fillStyle=`#FFFFFF`,e.fillText(`Collecting...`,f.x+10,p),p+=20):o.forEach(([t,n])=>{let r=`#00FF00`;n.average>16&&(r=`#FFFF00`),n.average>33&&(r=`#FF0000`),e.fillStyle=r;let i=`${t}: ${n.average.toFixed(2)}ms (${n.min.toFixed(1)}-${n.max.toFixed(1)})`;e.fillText(i,f.x+10,p),p+=20})}})},deactivate(e){e.api.unregisterRenderLayer(`performance-overlay`);let t=e.api.getData(`perfOverlayListeners`),n=e.timeline.getCanvas();t&&(n.removeEventListener(`mousedown`,t.onMouseDown,!0),n.removeEventListener(`mousemove`,t.onMouseMove,!0),window.removeEventListener(`mouseup`,t.onMouseUp,!0))}};export{n as t};
File without changes