timeline-canvas 1.3.0 → 1.4.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.
- package/README.md +21 -0
- package/README_CN.md +21 -0
- package/dist/ContextMenuPlugin-1N7od2I9.mjs +1 -0
- package/dist/{ContextMenuPlugin-HeXhKHl7.d.mts → ContextMenuPlugin-Ce29-J1v.d.mts} +1 -1
- package/dist/{DarkThemePlugin-Dy3wNEsj.d.mts → DarkThemePlugin-CLhvSrRp.d.mts} +1 -1
- package/dist/{DarkThemePlugin-GyV1mhmz.mjs → DarkThemePlugin-CqLyur3d.mjs} +1 -1
- package/dist/EventMediaPlugin-C2MC2ruT.mjs +1 -0
- package/dist/{EventMediaPlugin-oiYZdX1E.d.mts → EventMediaPlugin-DOIU5CZW.d.mts} +1 -1
- package/dist/{EventTooltipPlugin-BVStLFz2.d.mts → EventTooltipPlugin-BtU0ZtyW.d.mts} +1 -1
- package/dist/EventTooltipPlugin-Ch_xSklt.mjs +1 -0
- package/dist/{LightThemePlugin-ChMBy0bg.d.mts → LightThemePlugin-KFUJdO1V.d.mts} +1 -1
- package/dist/{LightThemePlugin-wHpjmbXj.mjs → LightThemePlugin-pQcTWONZ.mjs} +1 -1
- package/dist/PerformanceOverlayPlugin-BjEF-I5h.mjs +1 -0
- package/dist/{PerformanceOverlayPlugin-DFK_Clxo.d.mts → PerformanceOverlayPlugin-BmjL92Bg.d.mts} +1 -1
- package/dist/builtin-plugin/ContextMenuPlugin.d.mts +2 -2
- package/dist/builtin-plugin/ContextMenuPlugin.mjs +1 -1
- package/dist/builtin-plugin/DarkThemePlugin.d.mts +2 -2
- package/dist/builtin-plugin/DarkThemePlugin.mjs +1 -1
- package/dist/builtin-plugin/EventMediaPlugin.d.mts +2 -2
- package/dist/builtin-plugin/EventMediaPlugin.mjs +1 -1
- package/dist/builtin-plugin/EventTooltipPlugin.d.mts +2 -2
- package/dist/builtin-plugin/EventTooltipPlugin.mjs +1 -1
- package/dist/builtin-plugin/LightThemePlugin.d.mts +2 -2
- package/dist/builtin-plugin/LightThemePlugin.mjs +1 -1
- package/dist/builtin-plugin/MutexGuardPlugin.d.mts +1 -1
- package/dist/builtin-plugin/MutexGuardPlugin.mjs +1 -1
- package/dist/builtin-plugin/PerformanceOverlayPlugin.d.mts +2 -2
- package/dist/builtin-plugin/PerformanceOverlayPlugin.mjs +1 -1
- package/dist/index.d.mts +10 -11
- package/dist/index.mjs +1 -1
- package/dist/{types-CutIkjn4.d.mts → types-BovVI9wC.d.mts} +184 -36
- package/dist/types-Dc2ct_CM.mjs +1 -0
- package/package.json +53 -48
- package/dist/ContextMenuPlugin-6qe5xYCu.mjs +0 -1
- package/dist/EventMediaPlugin-CpPjf_yG.mjs +0 -1
- package/dist/EventTooltipPlugin-DNGXHYbN.mjs +0 -1
- package/dist/PerformanceOverlayPlugin-CcYPPPIx.mjs +0 -1
- package/dist/types-BvVk5Y9C.mjs +0 -1
|
@@ -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,
|
|
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,
|
|
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,23 @@ 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
|
+
//#endregion
|
|
530
|
+
//#region src/utils/i18n.d.ts
|
|
531
|
+
type TimelineMessageKey = keyof TimelineI18nMessages;
|
|
532
|
+
declare function createTimelineMessages(locale?: string, overrides?: Partial<TimelineI18nMessages>): TimelineI18nMessages;
|
|
533
|
+
//#endregion
|
|
534
|
+
//#region src/utils/performanceMonitor.d.ts
|
|
535
|
+
interface PerformanceStats {
|
|
536
|
+
average: number;
|
|
537
|
+
min: number;
|
|
538
|
+
max: number;
|
|
539
|
+
count: number;
|
|
540
|
+
total: number;
|
|
541
|
+
}
|
|
542
|
+
//#endregion
|
|
433
543
|
//#region src/core/managers/ChangeScheduler.d.ts
|
|
434
544
|
/**
|
|
435
545
|
* 状态变更类型
|
|
@@ -446,21 +556,21 @@ declare class Timeline {
|
|
|
446
556
|
private mouseHandler;
|
|
447
557
|
private wheelHandler;
|
|
448
558
|
private renderManager;
|
|
449
|
-
private guideLinesCache;
|
|
450
|
-
private guideLinesCacheTimestamp;
|
|
451
|
-
private readonly GUIDE_LINES_CACHE_TTL;
|
|
452
559
|
private eventListeners;
|
|
453
560
|
private pluginManager;
|
|
454
561
|
private logger;
|
|
455
562
|
private errorHandler;
|
|
456
563
|
private stateManager;
|
|
457
564
|
private eventIndexManager;
|
|
565
|
+
private eventMutationService;
|
|
566
|
+
private guideLineService;
|
|
567
|
+
private hitTestService;
|
|
458
568
|
private changeScheduler;
|
|
459
569
|
private currentThemePluginId;
|
|
460
570
|
constructor(canvasId: string, options?: TimelineOptions);
|
|
461
571
|
getCanvas(): HTMLCanvasElement;
|
|
462
|
-
usePlugin(plugin:
|
|
463
|
-
getLoadedPlugins():
|
|
572
|
+
usePlugin(plugin: TimelinePlugin): Promise<boolean>;
|
|
573
|
+
getLoadedPlugins(): TimelinePlugin[];
|
|
464
574
|
isPluginLoaded(pluginName: string): boolean;
|
|
465
575
|
removePlugin(pluginId: string): Promise<boolean>;
|
|
466
576
|
setTheme(theme: "light" | "dark"): Promise<boolean>;
|
|
@@ -499,8 +609,7 @@ declare class Timeline {
|
|
|
499
609
|
addTrack(): void;
|
|
500
610
|
removeTrack(): void;
|
|
501
611
|
autoRemoveEmptyLastTrack(): void;
|
|
502
|
-
|
|
503
|
-
addEvent(trackIndex: number, startTime: number, endTime: number, title: string, description?: string, customData?: Record<string, any>, readonly?: boolean): void;
|
|
612
|
+
addEvent(trackIndex: number, startTime: number, endTime: number, title: string, description?: string, customData?: Record<string, unknown>, readonly?: boolean): void;
|
|
504
613
|
updateEvent(trackIndex: number, eventIndex: number, updates: Partial<TimelineEvent>): boolean;
|
|
505
614
|
updateEventData(trackIndex: number, eventIndex: number, eventData: {
|
|
506
615
|
title?: string;
|
|
@@ -520,17 +629,7 @@ declare class Timeline {
|
|
|
520
629
|
* - 使用节流的边界滚动而非每帧滚动
|
|
521
630
|
*/
|
|
522
631
|
setTimeIndicatorDuringDrag(seconds: number): void;
|
|
523
|
-
/** 上一次边界滚动的时间戳 */
|
|
524
632
|
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
633
|
private scrollToTimeIndicatorThrottled;
|
|
535
634
|
private scrollToTimeIndicator;
|
|
536
635
|
zoom(factor: number): void;
|
|
@@ -539,6 +638,7 @@ declare class Timeline {
|
|
|
539
638
|
setEndTime(endTime: number): boolean;
|
|
540
639
|
getEndTime(): number;
|
|
541
640
|
formatTime(seconds: number): string;
|
|
641
|
+
t(key: TimelineMessageKey, params?: TimelineMessageParams): string;
|
|
542
642
|
setStatus(text: string): void;
|
|
543
643
|
getStatus(): string;
|
|
544
644
|
/**
|
|
@@ -557,6 +657,10 @@ declare class Timeline {
|
|
|
557
657
|
eventIndex: number;
|
|
558
658
|
edge: "left" | "right";
|
|
559
659
|
} | null;
|
|
660
|
+
private getEdgeScrollThrottle;
|
|
661
|
+
private getEdgeScrollTriggerMargin;
|
|
662
|
+
private getEdgeScrollViewportMargin;
|
|
663
|
+
private resolveEdgeScrollValue;
|
|
560
664
|
calculateGuideLines(fromTrackIndex: number, eventIndex: number, toTrackIndex: number, newStartTime: number, duration: number): Array<{
|
|
561
665
|
time: number;
|
|
562
666
|
type: "start" | "end";
|
|
@@ -583,18 +687,14 @@ declare class Timeline {
|
|
|
583
687
|
} | null;
|
|
584
688
|
isReadOnly(): boolean;
|
|
585
689
|
destroy(): void;
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
average: number;
|
|
591
|
-
min: number;
|
|
592
|
-
max: number;
|
|
593
|
-
count: number;
|
|
594
|
-
total: number;
|
|
690
|
+
private clearGuideLineCache;
|
|
691
|
+
private getPluginId;
|
|
692
|
+
private isThemePlugin;
|
|
693
|
+
private redrawAfterPluginChange;
|
|
595
694
|
}
|
|
596
695
|
//#endregion
|
|
597
696
|
//#region src/plugins/types.d.ts
|
|
697
|
+
type PluginLocalizedText = Partial<Record<TimelineLocale, string>>;
|
|
598
698
|
declare enum PluginType {
|
|
599
699
|
RENDER = "render",
|
|
600
700
|
EVENT_HANDLER = "event_handler",
|
|
@@ -613,6 +713,7 @@ interface PluginMetadata {
|
|
|
613
713
|
name: string;
|
|
614
714
|
version: string;
|
|
615
715
|
description: string;
|
|
716
|
+
descriptionI18n?: PluginLocalizedText;
|
|
616
717
|
author?: string;
|
|
617
718
|
type: PluginType;
|
|
618
719
|
priority?: PluginPriority;
|
|
@@ -622,24 +723,71 @@ type RenderLayerPosition = "background" | "overlay";
|
|
|
622
723
|
interface RenderLayer {
|
|
623
724
|
name: string;
|
|
624
725
|
position: RenderLayerPosition;
|
|
625
|
-
render: (ctx: CanvasRenderingContext2D, canvas: HTMLCanvasElement, config:
|
|
726
|
+
render: (ctx: CanvasRenderingContext2D, canvas: HTMLCanvasElement, config: TimelineConfig, state: TimelineState) => void;
|
|
626
727
|
}
|
|
728
|
+
/**
|
|
729
|
+
* 可被插件钩子拦截的核心渲染层
|
|
730
|
+
*/
|
|
731
|
+
type CoreRenderTarget = "tracks" | "timeline" | "guideLines" | "indicator" | "scrollbar" | "interaction";
|
|
732
|
+
/**
|
|
733
|
+
* 核心层钩子 — 允许插件拦截、修改或替换核心渲染层的行为
|
|
734
|
+
*
|
|
735
|
+
* `handler` 中调用 `next()` 执行默认渲染,不调用则完全替换默认行为。
|
|
736
|
+
* 多个钩子按注册顺序形成中间件链。
|
|
737
|
+
*
|
|
738
|
+
* @example
|
|
739
|
+
* ```ts
|
|
740
|
+
* // 修改轨道渲染:添加自定义背景后执行默认渲染
|
|
741
|
+
* registerCoreLayerHook({
|
|
742
|
+
* name: "custom-track-bg",
|
|
743
|
+
* target: "tracks",
|
|
744
|
+
* handler(ctx, canvas, config, state, next) {
|
|
745
|
+
* ctx.save();
|
|
746
|
+
* ctx.fillStyle = "rgba(0,0,255,0.05)";
|
|
747
|
+
* ctx.fillRect(0, 0, canvas.width, canvas.height);
|
|
748
|
+
* ctx.restore();
|
|
749
|
+
* next(); // 执行默认轨道渲染
|
|
750
|
+
* }
|
|
751
|
+
* });
|
|
752
|
+
*
|
|
753
|
+
* // 完全替换时间轴刻度渲染
|
|
754
|
+
* registerCoreLayerHook({
|
|
755
|
+
* name: "custom-timeline",
|
|
756
|
+
* target: "timeline",
|
|
757
|
+
* handler(ctx, canvas, config, state, _next) {
|
|
758
|
+
* // 不调用 next(),完全自定义绘制
|
|
759
|
+
* drawMyCustomTimeline(ctx, canvas, config, state);
|
|
760
|
+
* }
|
|
761
|
+
* });
|
|
762
|
+
* ```
|
|
763
|
+
*/
|
|
764
|
+
interface CoreLayerHook {
|
|
765
|
+
/** 钩子名称,唯一标识 */
|
|
766
|
+
name: string;
|
|
767
|
+
/** 目标核心渲染层 */
|
|
768
|
+
target: CoreRenderTarget;
|
|
769
|
+
/** 钩子处理函数 */
|
|
770
|
+
handler: (ctx: CanvasRenderingContext2D, canvas: HTMLCanvasElement, config: TimelineConfig, state: TimelineState, next: () => void) => void;
|
|
771
|
+
}
|
|
772
|
+
type PluginEventHandler = (...args: unknown[]) => unknown;
|
|
627
773
|
interface PluginAPI {
|
|
628
774
|
registerRenderLayer: (layer: RenderLayer) => void;
|
|
629
775
|
unregisterRenderLayer: (name: string) => void;
|
|
630
|
-
|
|
631
|
-
|
|
776
|
+
registerCoreLayerHook: (hook: CoreLayerHook) => void;
|
|
777
|
+
unregisterCoreLayerHook: (name: string) => void;
|
|
778
|
+
registerEventHandler: (event: string, handler: PluginEventHandler) => void;
|
|
779
|
+
unregisterEventHandler: (event: string, handler: PluginEventHandler) => void;
|
|
632
780
|
showNotification: (message: string, type?: "info" | "warning" | "error") => void;
|
|
633
|
-
getData: (key: string) =>
|
|
634
|
-
setData: (key: string, value:
|
|
781
|
+
getData: (key: string) => unknown;
|
|
782
|
+
setData: (key: string, value: unknown) => void;
|
|
635
783
|
setPerformanceProvider: (provider: PerformanceProvider) => void;
|
|
636
784
|
getPerformanceStats: () => Map<string, PerformanceStats>;
|
|
637
785
|
getFPS: () => number;
|
|
638
786
|
}
|
|
639
787
|
interface PluginContext {
|
|
640
788
|
timeline: Timeline;
|
|
641
|
-
config:
|
|
642
|
-
state:
|
|
789
|
+
config: TimelineConfig;
|
|
790
|
+
state: TimelineState;
|
|
643
791
|
api: PluginAPI;
|
|
644
792
|
}
|
|
645
793
|
interface TimelinePlugin {
|
|
@@ -656,4 +804,4 @@ interface PerformanceProvider {
|
|
|
656
804
|
getFPS: () => number;
|
|
657
805
|
}
|
|
658
806
|
//#endregion
|
|
659
|
-
export {
|
|
807
|
+
export { TimelineCallbacks as A, ZoomData as B, EventEditData as C, InteractionTarget as D, EventUpdateData as E, TimelineLocale as F, TimelineMessageParams as I, TimelineOptions as L, TimelineConfig as M, TimelineEvent as N, LoadDataFormat as O, TimelineI18nMessages as P, TimelineState as R, EventDeleteData as S, EventTextStyle as T, ContextMenuData as _, PluginLocalizedText as a, EventAddData as b, PluginType as c, TimelinePlugin as d, Timeline as f, getCurrentTime as g, formatTime as h, PluginContext as i, TimelineColors as j, TimeIndicatorMoveData as k, RenderLayer as l, createTimelineMessages as m, CoreRenderTarget as n, PluginMetadata as o, ChangeType as p, PluginAPI as r, PluginPriority as s, CoreLayerHook as t, RenderLayerPosition as u, ContextMenuItem as v, EventMoveData as w, EventClickData as x, ContextMenuStyle as y, Track as z };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
let e=function(e){return e.RENDER=`render`,e.EVENT_HANDLER=`event_handler`,e.DATA_SOURCE=`data_source`,e.THEME=`theme`,e.TOOL=`tool`,e.EXTENSION=`extension`,e}({}),t=function(e){return e[e.LOW=0]=`LOW`,e[e.NORMAL=50]=`NORMAL`,e[e.HIGH=100]=`HIGH`,e[e.CRITICAL=200]=`CRITICAL`,e}({});export{e as n,t};
|
package/package.json
CHANGED
|
@@ -1,48 +1,53 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "timeline-canvas",
|
|
3
|
-
"version": "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": "
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
"
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
"
|
|
37
|
-
|
|
38
|
-
"
|
|
39
|
-
"
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
"
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "timeline-canvas",
|
|
3
|
+
"version": "1.4.0",
|
|
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
|
+
}
|
|
53
|
+
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{i as e}from"./Logger-CfVK3yFL.mjs";import{t}from"./types-BvVk5Y9C.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{t as e}from"./types-BvVk5Y9C.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{t}from"./types-BvVk5Y9C.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{t as e}from"./performanceMonitor-BBherdD8.mjs";import{t}from"./types-BvVk5Y9C.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};
|
package/dist/types-BvVk5Y9C.mjs
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
let e=function(e){return e.RENDER=`render`,e.EVENT_HANDLER=`event_handler`,e.DATA_SOURCE=`data_source`,e.THEME=`theme`,e.TOOL=`tool`,e.EXTENSION=`extension`,e}({});export{e as t};
|