Эх сурвалжийг харах

Allow to override custom keyframe renderer.

Ievgen Naida 1 жил өмнө
parent
commit
b43787f486

+ 2 - 0
CHANGELOG.md

@@ -11,6 +11,8 @@
 - Updated dev packages to the latest versions.
 - Added groups stroke and border radius support.
 - BUG FIX: group is rendered for one keyframe.
+- BUG FIX: missing timelineGroupStyle export.
+- Added demo for the custom keyframe rendering (image rendering).
 
 ## [2.3.2] - 10.04.2024
 

+ 34 - 5
demo/demo.js

@@ -6,6 +6,10 @@
 // @ts-check
 var outlineContainer = document.getElementById('outline-container');
 
+var keyframeWithCustomImage = {
+    val: 500
+}
+
 function generateModel() {
     /** @type {import('../lib/animation-timeline').TimelineGroupStyle} */
     const groupA = {
@@ -118,7 +122,7 @@ function generateModel() {
                 ],
             },
             {
-                title: 'Groups (Limited)',
+                title: 'Groups (MIN, MAX Limited)',
                 keyframes: [
                     {
                         val: 40,
@@ -149,7 +153,7 @@ function generateModel() {
                 ],
             },
             {
-                title: 'Show 3 lanes as one outline',
+                title: '3 Lanes For One Node',
                 keyframesDraggable: false,
                 style: {
                     fillColor: "black",
@@ -175,7 +179,7 @@ function generateModel() {
                 ],
             },
             {
-                title: 'Show 3 lanes as one outline',
+                title: '3 Lanes For One Node',
                 keyframesDraggable: false,
                 style: {
                     fillColor: "black",
@@ -201,7 +205,7 @@ function generateModel() {
                 ],
             },
             {
-                title: 'Show 3 lanes as one outline',
+                title: '3 Lanes For One Node',
                 keyframesDraggable: false,
                 style: {
                     fillColor: "black",
@@ -319,7 +323,12 @@ function generateModel() {
                     },
                 ],
             },
-            {},
+            {
+                title: "Custom Keyframe (Image)",
+                keyframes: [
+                    keyframeWithCustomImage
+                ]
+            },
             {
                 title: 'Max Value (Not Draggable)',
                 max: 4000,
@@ -374,6 +383,7 @@ function generateModel() {
 }
 const timelineModel = generateModel();
 
+
 // Log message to the screen
 var logMessage = function (message, logPanel = 1) {
     if (message) {
@@ -393,6 +403,25 @@ var logDraggingMessage = function (object, eventName) {
 // @ts-ignore
 var timeline = new timelineModule.Timeline();
 
+const defaultKeyframesRenderer = timeline._renderKeyframe.bind(timeline);
+
+// Custom Image
+const image = new Image();
+image.src = 'https://material-icons.github.io/material-icons-png/png/white/public/baseline-2x.png'; // replace with your image path
+image.onload = () => {
+    timeline.redraw();
+};
+// Set custom keyframes renderer
+timeline._renderKeyframe = (ctx, keyframeViewModel) => {
+    if (keyframeViewModel.model === keyframeWithCustomImage) {
+        ctx.drawImage(image, keyframeViewModel.size.x - 5, keyframeViewModel.size.y - 5, keyframeViewModel.size.width + 5, keyframeViewModel.size.height + 5);
+    } else {
+        // Use default renderer
+        defaultKeyframesRenderer(ctx, keyframeViewModel);
+    }
+}
+
+
 timeline.initialize({ id: 'timeline', headerHeight: 45 }, timelineModel);
 
 // Select all elements on key down

+ 68 - 61
lib/animation-timeline.js

@@ -3027,11 +3027,8 @@ var Timeline = /*#__PURE__*/function (_TimelineEventsEmitte) {
         if (!_this._ctx) {
           return;
         }
-        var row = keyframeViewModel.rowViewModel.model;
         var size = keyframeViewModel.size;
-        var keyframe = keyframeViewModel.model;
         if (size) {
-          var _keyframeViewModel$gr;
           var x = _this._getSharp(size.x);
           var y = size.y;
           var bounds = _this._cutBounds({
@@ -3044,69 +3041,79 @@ var Timeline = /*#__PURE__*/function (_TimelineEventsEmitte) {
             return;
           }
           _this._ctx.save();
-
-          // Performance FIX: use clip only  when we are in the collision! Clip is slow!
-          // Other keyframes should be hidden by bounds check.
-          // Note: clip with just render part of the keyframe
-          if (bounds && bounds.overlapY) {
-            _this._ctx.beginPath();
-            _this._ctx.rect(0, TimelineStyleUtils.headerHeight(_this._options), _this._canvasClientWidth(), _this._canvasClientWidth());
-            _this._ctx.clip();
-          }
-          var shape = keyframeViewModel.shape;
-          if (shape === TimelineKeyframeShape.None) {
-            return;
-          }
-          var rowStyle = row.style || null;
-          var groupModel = (keyframeViewModel === null || keyframeViewModel === void 0 || (_keyframeViewModel$gr = keyframeViewModel.groupViewModel) === null || _keyframeViewModel$gr === void 0 ? void 0 : _keyframeViewModel$gr.groupModel) || null;
-          var keyframeColor = keyframe.selected ? TimelineStyleUtils.keyframeSelectedFillColor(keyframe, groupModel, rowStyle, _this._options) : TimelineStyleUtils.keyframeFillColor(keyframe, groupModel, rowStyle, _this._options);
-          var border = TimelineStyleUtils.keyframeStrokeThickness(keyframe, groupModel, rowStyle, _this._options);
-          var strokeColor = '';
-          if (border > 0) {
-            if (keyframe.selected) {
-              strokeColor = TimelineStyleUtils.keyframeSelectedStrokeColor(keyframe, groupModel, rowStyle, _this._options);
-            } else {
-              strokeColor = TimelineStyleUtils.keyframeStrokeColor(keyframe, groupModel, rowStyle, _this._options);
-            }
-          }
-          if (shape == TimelineKeyframeShape.Rhomb) {
-            _this._ctx.beginPath();
-            _this._ctx.translate(x, y);
-            _this._ctx.rotate(45 * Math.PI / 180);
-            if (border > 0 && strokeColor) {
-              _this._ctx.fillStyle = strokeColor;
-              _this._ctx.rect(-size.width / 2, -size.height / 2, size.width, size.height);
-              _this._ctx.fill();
+          try {
+            // Performance FIX: use clip only  when we are in the collision! Clip is slow!
+            // Other keyframes should be hidden by bounds check.
+            // Note: clip with just render part of the keyframe
+            if (bounds && bounds.overlapY) {
+              _this._ctx.beginPath();
+              _this._ctx.rect(0, TimelineStyleUtils.headerHeight(_this._options), _this._canvasClientWidth(), _this._canvasClientWidth());
+              _this._ctx.clip();
             }
-            _this._ctx.fillStyle = keyframeColor;
-            // draw main keyframe data with offset.
-            _this._ctx.translate(border, border);
-            _this._ctx.rect(-size.width / 2, -size.height / 2, size.width - border * 2, size.height - border * 2);
-            _this._ctx.fill();
-          } else if (shape == TimelineKeyframeShape.Circle) {
-            _this._ctx.beginPath();
-            if (border > 0 && strokeColor) {
-              _this._ctx.fillStyle = strokeColor;
-              _this._ctx.arc(x, y, size.height, 0, 2 * Math.PI);
-            }
-            _this._ctx.fillStyle = keyframeColor;
-            _this._ctx.arc(x, y, size.height - border, 0, 2 * Math.PI);
-            _this._ctx.fill();
-          } else if (shape == TimelineKeyframeShape.Rect) {
-            _this._ctx.beginPath();
-            if (border > 0 && strokeColor) {
-              _this._ctx.fillStyle = strokeColor;
-              _this._ctx.rect(x, y, size.width, size.height);
-              _this._ctx.fill();
-            }
-            _this._ctx.fillStyle = keyframeColor;
-            _this._ctx.rect(x + border, y + border, size.width - border, size.height - border);
-            _this._ctx.fill();
-          }
+            _this._renderKeyframe(_this._ctx, keyframeViewModel);
+          } finally {}
           _this._ctx.restore();
         }
       });
     });
+    timeline_defineProperty(_this, "_renderKeyframe", function (ctx, keyframeViewModel) {
+      var _keyframeViewModel$gr;
+      var shape = keyframeViewModel.shape;
+      if (shape === TimelineKeyframeShape.None) {
+        return;
+      }
+      var size = keyframeViewModel.size;
+      var x = _this._getSharp(size.x);
+      var y = size.y;
+      var keyframe = keyframeViewModel.model;
+      var row = keyframeViewModel.rowViewModel.model;
+      var rowStyle = row.style || null;
+      var groupModel = (keyframeViewModel === null || keyframeViewModel === void 0 || (_keyframeViewModel$gr = keyframeViewModel.groupViewModel) === null || _keyframeViewModel$gr === void 0 ? void 0 : _keyframeViewModel$gr.groupModel) || null;
+      var keyframeColor = keyframe.selected ? TimelineStyleUtils.keyframeSelectedFillColor(keyframe, groupModel, rowStyle, _this._options) : TimelineStyleUtils.keyframeFillColor(keyframe, groupModel, rowStyle, _this._options);
+      var border = TimelineStyleUtils.keyframeStrokeThickness(keyframe, groupModel, rowStyle, _this._options);
+      var strokeColor = '';
+      if (border > 0) {
+        if (keyframe.selected) {
+          strokeColor = TimelineStyleUtils.keyframeSelectedStrokeColor(keyframe, groupModel, rowStyle, _this._options);
+        } else {
+          strokeColor = TimelineStyleUtils.keyframeStrokeColor(keyframe, groupModel, rowStyle, _this._options);
+        }
+      }
+      if (shape == TimelineKeyframeShape.Rhomb) {
+        ctx.beginPath();
+        ctx.translate(x, y);
+        ctx.rotate(45 * Math.PI / 180);
+        if (border > 0 && strokeColor) {
+          ctx.fillStyle = strokeColor;
+          ctx.rect(-size.width / 2, -size.height / 2, size.width, size.height);
+          ctx.fill();
+        }
+        ctx.fillStyle = keyframeColor;
+        // draw main keyframe data with offset.
+        ctx.translate(border, border);
+        ctx.rect(-size.width / 2, -size.height / 2, size.width - border * 2, size.height - border * 2);
+        ctx.fill();
+      } else if (shape == TimelineKeyframeShape.Circle) {
+        ctx.beginPath();
+        if (border > 0 && strokeColor) {
+          ctx.fillStyle = strokeColor;
+          ctx.arc(x, y, size.height, 0, 2 * Math.PI);
+        }
+        ctx.fillStyle = keyframeColor;
+        ctx.arc(x, y, size.height - border, 0, 2 * Math.PI);
+        ctx.fill();
+      } else if (shape == TimelineKeyframeShape.Rect) {
+        ctx.beginPath();
+        if (border > 0 && strokeColor) {
+          ctx.fillStyle = strokeColor;
+          ctx.rect(x, y, size.width, size.height);
+          ctx.fill();
+        }
+        ctx.fillStyle = keyframeColor;
+        ctx.rect(x + border, y + border, size.width - border, size.height - border);
+        ctx.fill();
+      }
+    });
     timeline_defineProperty(_this, "_renderSelectionRect", function () {
       if (_this._drag || !_this._ctx || !_this._canvas) {
         return;

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 0 - 0
lib/animation-timeline.js.map


Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 0 - 0
lib/animation-timeline.min.js


+ 1 - 0
lib/timeline.d.ts

@@ -407,6 +407,7 @@ export declare class Timeline extends TimelineEventsEmitter {
     _getKeyframesGroupSize: (groupViewModel: TimelineGroupViewModel, rowViewModel: TimelineRowViewModel) => DOMRect;
     _getKeyframePosition: (keyframe: TimelineKeyframe, groupViewModel: TimelineGroupViewModel, rowViewModel: TimelineRowViewModel, keyframeShape: TimelineKeyframeShape) => DOMRect | null;
     _renderKeyframes: () => void;
+    _renderKeyframe: (ctx: CanvasRenderingContext2D, keyframeViewModel: TimelineKeyframeViewModel) => void;
     _renderSelectionRect: () => void;
     _renderBackground: () => void;
     _renderTimeline: () => void;

+ 75 - 64
src/timeline.ts

@@ -1990,9 +1990,8 @@ export class Timeline extends TimelineEventsEmitter {
       if (!this._ctx) {
         return;
       }
-      const row = keyframeViewModel.rowViewModel.model;
       const size = keyframeViewModel.size;
-      const keyframe = keyframeViewModel.model;
+
       if (size) {
         const x = this._getSharp(size.x);
         const y = size.y;
@@ -2008,75 +2007,87 @@ export class Timeline extends TimelineEventsEmitter {
 
         this._ctx.save();
 
-        // Performance FIX: use clip only  when we are in the collision! Clip is slow!
-        // Other keyframes should be hidden by bounds check.
-        // Note: clip with just render part of the keyframe
-        if (bounds && bounds.overlapY) {
-          this._ctx.beginPath();
-          this._ctx.rect(0, TimelineStyleUtils.headerHeight(this._options), this._canvasClientWidth(), this._canvasClientWidth());
-          this._ctx.clip();
-        }
-
-        const shape = keyframeViewModel.shape;
-        if (shape === TimelineKeyframeShape.None) {
-          return;
-        }
-        const rowStyle = row.style || null;
-        const groupModel = keyframeViewModel?.groupViewModel?.groupModel || null;
-        const keyframeColor = keyframe.selected
-          ? TimelineStyleUtils.keyframeSelectedFillColor(keyframe, groupModel, rowStyle, this._options)
-          : TimelineStyleUtils.keyframeFillColor(keyframe, groupModel, rowStyle, this._options);
-        const border = TimelineStyleUtils.keyframeStrokeThickness(keyframe, groupModel, rowStyle, this._options);
-        let strokeColor = '';
-        if (border > 0) {
-          if (keyframe.selected) {
-            strokeColor = TimelineStyleUtils.keyframeSelectedStrokeColor(keyframe, groupModel, rowStyle, this._options);
-          } else {
-            strokeColor = TimelineStyleUtils.keyframeStrokeColor(keyframe, groupModel, rowStyle, this._options);
+        try {
+          // Performance FIX: use clip only  when we are in the collision! Clip is slow!
+          // Other keyframes should be hidden by bounds check.
+          // Note: clip with just render part of the keyframe
+          if (bounds && bounds.overlapY) {
+            this._ctx.beginPath();
+            this._ctx.rect(0, TimelineStyleUtils.headerHeight(this._options), this._canvasClientWidth(), this._canvasClientWidth());
+            this._ctx.clip();
           }
-        }
 
-        if (shape == TimelineKeyframeShape.Rhomb) {
-          this._ctx.beginPath();
-          this._ctx.translate(x, y);
-          this._ctx.rotate((45 * Math.PI) / 180);
-          if (border > 0 && strokeColor) {
-            this._ctx.fillStyle = strokeColor;
-            this._ctx.rect(-size.width / 2, -size.height / 2, size.width, size.height);
-            this._ctx.fill();
-          }
+          this._renderKeyframe(this._ctx, keyframeViewModel);
+        } finally {
+        }
+        this._ctx.restore();
+      }
+    });
+  };
 
-          this._ctx.fillStyle = keyframeColor;
-          // draw main keyframe data with offset.
-          this._ctx.translate(border, border);
-          this._ctx.rect(-size.width / 2, -size.height / 2, size.width - border * 2, size.height - border * 2);
-          this._ctx.fill();
-        } else if (shape == TimelineKeyframeShape.Circle) {
-          this._ctx.beginPath();
-          if (border > 0 && strokeColor) {
-            this._ctx.fillStyle = strokeColor;
-            this._ctx.arc(x, y, size.height, 0, 2 * Math.PI);
-          }
-          this._ctx.fillStyle = keyframeColor;
-          this._ctx.arc(x, y, size.height - border, 0, 2 * Math.PI);
-          this._ctx.fill();
-        } else if (shape == TimelineKeyframeShape.Rect) {
-          this._ctx.beginPath();
+  _renderKeyframe = (ctx: CanvasRenderingContext2D, keyframeViewModel: TimelineKeyframeViewModel): void => {
+    const shape = keyframeViewModel.shape;
+    if (shape === TimelineKeyframeShape.None) {
+      return;
+    }
+    const size = keyframeViewModel.size;
+    const x = this._getSharp(size.x);
+    const y = size.y;
+
+    const keyframe = keyframeViewModel.model;
+    const row = keyframeViewModel.rowViewModel.model;
+    const rowStyle = row.style || null;
+    const groupModel = keyframeViewModel?.groupViewModel?.groupModel || null;
+    const keyframeColor = keyframe.selected
+      ? TimelineStyleUtils.keyframeSelectedFillColor(keyframe, groupModel, rowStyle, this._options)
+      : TimelineStyleUtils.keyframeFillColor(keyframe, groupModel, rowStyle, this._options);
+    const border = TimelineStyleUtils.keyframeStrokeThickness(keyframe, groupModel, rowStyle, this._options);
+    let strokeColor = '';
+    if (border > 0) {
+      if (keyframe.selected) {
+        strokeColor = TimelineStyleUtils.keyframeSelectedStrokeColor(keyframe, groupModel, rowStyle, this._options);
+      } else {
+        strokeColor = TimelineStyleUtils.keyframeStrokeColor(keyframe, groupModel, rowStyle, this._options);
+      }
+    }
 
-          if (border > 0 && strokeColor) {
-            this._ctx.fillStyle = strokeColor;
-            this._ctx.rect(x, y, size.width, size.height);
-            this._ctx.fill();
-          }
+    if (shape == TimelineKeyframeShape.Rhomb) {
+      ctx.beginPath();
+      ctx.translate(x, y);
+      ctx.rotate((45 * Math.PI) / 180);
+      if (border > 0 && strokeColor) {
+        ctx.fillStyle = strokeColor;
+        ctx.rect(-size.width / 2, -size.height / 2, size.width, size.height);
+        ctx.fill();
+      }
 
-          this._ctx.fillStyle = keyframeColor;
-          this._ctx.rect(x + border, y + border, size.width - border, size.height - border);
-          this._ctx.fill();
-        }
+      ctx.fillStyle = keyframeColor;
+      // draw main keyframe data with offset.
+      ctx.translate(border, border);
+      ctx.rect(-size.width / 2, -size.height / 2, size.width - border * 2, size.height - border * 2);
+      ctx.fill();
+    } else if (shape == TimelineKeyframeShape.Circle) {
+      ctx.beginPath();
+      if (border > 0 && strokeColor) {
+        ctx.fillStyle = strokeColor;
+        ctx.arc(x, y, size.height, 0, 2 * Math.PI);
+      }
+      ctx.fillStyle = keyframeColor;
+      ctx.arc(x, y, size.height - border, 0, 2 * Math.PI);
+      ctx.fill();
+    } else if (shape == TimelineKeyframeShape.Rect) {
+      ctx.beginPath();
 
-        this._ctx.restore();
+      if (border > 0 && strokeColor) {
+        ctx.fillStyle = strokeColor;
+        ctx.rect(x, y, size.width, size.height);
+        ctx.fill();
       }
-    });
+
+      ctx.fillStyle = keyframeColor;
+      ctx.rect(x + border, y + border, size.width - border, size.height - border);
+      ctx.fill();
+    }
   };
 
   _renderSelectionRect = (): void => {

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно