فهرست منبع

Initialization is simplified. Only div with id is required. Added dark scheme.

Ievgen Naida 6 سال پیش
والد
کامیت
1f7747b18c
3فایلهای تغییر یافته به همراه236 افزوده شده و 178 حذف شده
  1. 15 2
      README.md
  2. 101 53
      animation-timeline.js
  3. 120 123
      index.html

+ 15 - 2
README.md

@@ -1,3 +1,16 @@
-# js-animation-timeline-control
+# js-animation-timeline-control (0.0.1-alpha)
 
-Pure javascript html 5 implementation of the amimation timeline editor.
+Animation timeline is a vanilla JavaScript, no-dependency canvas control to render the animation keyframes.
+
+Features:
+
+- Fast and customizable, rendered on a canvas.
+- Snap, Zoom, Pan mode, multiple keyframes selection.
+- Keyboard support.
+- Drag mutliple keyframes and keyframe ranges.
+- Area virtualization - only small displayed area is rendered.
+- Native browser scrollbars are used.
+
+## License
+
+MIT

+ 101 - 53
animation-timeline.js

@@ -36,28 +36,28 @@ var animationTimeline = function (window, document) {
 		// additional left margin to start the gauge from
 		leftMarginPx: 25,
 		minTimelineToDispayMs: 5000,
-		headerBackground: 'black',
+		headerBackground: '#101011',
 		selectedLaneColor: '#333333',
+		backgroundColor: '#101011',
+		timeIndicatorColor: 'DarkOrange',
+		labelsColor: '#D5D5D5',
+		tickColor: '#D5D5D5',
+		selectionColor: 'White',
 		// lanes colors
-		laneColor: 'white',
+		laneColor: '#252526', //'#252526',37373D
 		alternateLaneColor: 'black',//333333
-		useAlternateLaneColor: false,
-		keyframesLaneColor: 'red',
+		keyframesLaneColor: '#094771',
 		// keyframe color. can be overrided by a keyframe 'color' property.
-		keyframeColor: 'Yellow',
+		keyframeColor: 'red',
 		// selected keyframe color. can be overrider by a keyframe 'selectedColor' property.
 		selectedKeyframeColor: 'DarkOrange',
 		keyframeBorderColor: 'Black',
+		useAlternateLaneColor: false,
 		keyframeBorderThicknessPx: 0.2,
 		// can be a number or 'auto'. can be overriden by 'keyframe.size'. Auto is calculated based on the laneHeightPx.
 		keyframeSizePx: 'auto',
-		backgroundColor: 'black',//1E1E1E
-		timeIndicatorColor: 'DarkOrange',
-		labelsColor: '#D5D5D5',
-		tickColor: '#D5D5D5',
-		selectionColor: 'White',
 		laneHeightPx: 24,
-		laneMarginPX: 1,
+		laneMarginPx: 2,
 		// Size of the lane in pixels. Can be 'auto' than size is based on the 'laneHeightPx'. can be overriden by lane 'lane.keyframesLaneSizePx'. 
 		keyframesLaneSizePx: 'auto',
 		// Allow to drag keyframes lane.
@@ -70,7 +70,6 @@ var animationTimeline = function (window, document) {
 		// scroll by drag speed (from 0 to 1)
 		scrollByDragSpeed: 0.12,
 		id: '',
-		scrollId: '',
 		// Use from and to range to limit the animation payload: 
 		useTimelineAnimationRange: false,
 		from: null,
@@ -205,10 +204,50 @@ var animationTimeline = function (window, document) {
 
 
 	this.initialize = function (options, lanes) {
-		var timeLine = {
-			ms: 0,
+
+		var scrollContainer = document.getElementById(options.id);
+		if (!scrollContainer) {
+			console.log('options.scrollId is mandatory!');
+			return;
+		}
+
+
+		scrollContainer.style.overflow = "scroll";
+		scrollContainer.style.position = "relative";
+		scrollContainer.style.touchAction = "none";
+		var size = document.createElement("div");
+		var canvas = document.createElement("canvas");
+
+		if (!canvas || !canvas.getContext) {
+			console.log('Cannot initialize canvas context.');
+			return null;
 		}
 
+		// Generate size container:
+		canvas.style.cssText = 'image-rendering: -moz-crisp-edges;' +
+			' image-rendering: -webkit-crisp-edges;' +
+			'image-rendering: pixelated;' +
+			'image-rendering: crisp-edges;' +
+			' user-select: none;' +
+			'-webkit-user-select: none;' +
+			'-khtml-user-select: none;' +
+			'-moz-user-select: none;' +
+			'-o-user-select: none;' +
+			'user-select: none;' +
+			'touch-action: none;' +
+			'position: absolute;' +
+			'top: 0;' +
+			'left: 0;' +
+			'width: 100%;' +
+			'padding: inherit' +
+			'height: 100%;';
+
+		size.style.width = size.style.height = canvas.style.width = canvas.style.height = "100%";
+		// add the text node to the newly created div
+		scrollContainer.appendChild(size);
+		scrollContainer.appendChild(canvas);
+
+
 		// Merge options with the default:
 		for (var key in defaultOptions) {
 			if (Object.prototype.hasOwnProperty.call(defaultOptions, key) && options[key] == undefined) {
@@ -216,6 +255,10 @@ var animationTimeline = function (window, document) {
 			}
 		}
 
+		if (options.backgroundColor) {
+			scrollContainer.style.background = options.backgroundColor;
+		}
+
 		if (!options.stepPx) {
 			options.stepPx = defaultOptions.stepPx;
 		}
@@ -227,6 +270,12 @@ var animationTimeline = function (window, document) {
 			}
 		}
 
+
+
+
+		let timeLine = {
+			ms: 0,
+		}
 		let startPos = null;
 		let currentPos = null;
 		let selectionRect = null;
@@ -238,19 +287,6 @@ var animationTimeline = function (window, document) {
 		let lastCallDate = null;
 		let isPanStarted = false;
 		let isPanMode = false;
-		var scrollContainer = document.getElementById(options.scrollId);
-		if (!scrollContainer) {
-			console.log('options.scrollId is mandatory!');
-			return;
-		}
-		var canvas = document.getElementById(options.id);
-		var size = document.getElementById(options.sizeId);
-
-		if (!canvas || !canvas.getContext) {
-			console.log('Cannot find canvas by id:' + options.id);
-			return null;
-		}
-
 		var ctx = canvas.getContext("2d");
 		ctx.drawLine = function (x1, y1, x2, y2) {
 			this.moveTo(x1, y1);
@@ -421,35 +457,46 @@ var animationTimeline = function (window, document) {
 			}
 		});
 
-		scrollContainer.addEventListener('scroll', function () {
-			var left = scrollContainer.scrollLeft + 'px';
-			if (canvas.style.left != left) {
-				canvas.style.left = left;
-			}
-			var top = scrollContainer.scrollTop + 'px';
-			if (top !== canvas.style.top) {
-				canvas.style.top = top;
-			}
+		if (scrollContainer) {
+			scrollContainer.addEventListener('scroll', function (args) {
+				var left = scrollContainer.scrollLeft + 'px';
+				if (canvas.style.left != left) {
+					canvas.style.left = left;
+				}
+				var top = scrollContainer.scrollTop + 'px';
+				if (top !== canvas.style.top) {
+					canvas.style.top = top;
+				}
 
-			if (scrollingTimeRef) {
-				clearTimeout(scrollingTimeRef);
-				scrollingTimeRef = null;
-			}
+				if (scrollingTimeRef) {
+					clearTimeout(scrollingTimeRef);
+					scrollingTimeRef = null;
+				}
 
-			// Set a timeout to run event 'scrolling end'.
-			scrollingTimeRef = setTimeout(function () {
-				if (!isPanStarted) {
-					if (scrollingTimeRef) {
-						clearTimeout(scrollingTimeRef);
-						scrollingTimeRef = null;
+				// Set a timeout to run event 'scrolling end'.
+				scrollingTimeRef = setTimeout(function () {
+					if (!isPanStarted) {
+						if (scrollingTimeRef) {
+							clearTimeout(scrollingTimeRef);
+							scrollingTimeRef = null;
+						}
+						rescale();
 					}
-					rescale();
-				}
 
-			}, 500);
+				}, 500);
 
-			redraw();
-		});
+				redraw();
+				let scrollData = {
+					args: args,
+					scrollLeft: scrollContainer.scrollLeft,
+					scrollTop: scrollContainer.scrollTop,
+					clientHeight: scrollContainer.scrollHeight,
+					clientWidth: scrollContainer.clientWidth
+				};
+
+				emit('scroll', scrollData);
+			});
+		}
 
 		window.addEventListener('blur', function () {
 			cleanUpSelection();
@@ -1248,7 +1295,7 @@ var animationTimeline = function (window, document) {
 		function getLanePosition(laneIndex) {
 			let laneY = options.headerHeight +
 				laneIndex * options.laneHeightPx +
-				laneIndex * options.laneMarginPX;
+				laneIndex * options.laneMarginPx;
 			return laneY;
 		}
 
@@ -1553,7 +1600,7 @@ var animationTimeline = function (window, document) {
 		}
 
 		// emit event.
-		this.emit = function (topic, args) {
+		function emit(topic, args) {
 			for (var i = subscriptions.length - 1; i >= 0; i--) {
 				var sub = subscriptions[i];
 				if (sub.topic == topic && sub.callback) {
@@ -1562,6 +1609,7 @@ var animationTimeline = function (window, document) {
 			}
 		}
 
+		this.emit = emit;
 		/**
 		 * Remove the event from the subscriptions list.
 		 * @param {*} topic 

+ 120 - 123
index.html

@@ -1,137 +1,134 @@
 <!DOCTYPE html>
 <html>
+  <head>
+    <style>
+      head,
+      body {
+        margin: 0px;
+      }
+      #timeline {
+        box-sizing: border-box;
+        width: 100%;
+        height: 50vh;
+        scrollbar-color: gray #161616;
+      }
+      ::-webkit-scrollbar {
+        background: #161616;
+        color: gray;
+      }
 
-<head>
-  <style>
-    #timeline-canvas-container {
-      position: absolute;
-      top: 0;
-      right: 0;
-      bottom: 0;
-    }
-
-    #timeline-size-content {
-      width: 100px;
-      height: 100%;
-    }
-
-    #timeline-scroll-container {
-      border: 1px solid #d3d3d3;
-      background: white;
-      overflow: scroll;
-      max-width: 100%;
-      height: 400px;
-      position: relative;
-      box-sizing: border-box;
-      width: 100%;
-      touch-action: none;
-    }
-
-    #timeline {
-
-      image-rendering: -moz-crisp-edges;
-      image-rendering: -webkit-crisp-edges;
-      image-rendering: pixelated;
-      image-rendering: crisp-edges;
-      user-select: none;
-      -webkit-user-select: none;
-      -khtml-user-select: none;
-      -moz-user-select: none;
-      -o-user-select: none;
-      user-select: none;
-      touch-action: none;
-      position: absolute;
-      top: 0;
-      left: 0;
-      width: 100%;
-      height: 100%;
-      box-sizing: border-box;
+      ::-webkit-scrollbar-thumb {
+        background: gray;
+      }
 
-    }
-  </style>
+      ::-webkit-scrollbar-corner {
+        background: #161616;
+      }
+    </style>
 
-  <script src="animation-timeline.js" type="text/javascript">
-  </script>
-</head>
+    <script src="animation-timeline.js" type="text/javascript"></script>
+  </head>
 
-<body>
-  <div id="timeline-scroll-container">
-    <div id="timeline-size-content">
+  <body>
+    <div>
+      <div id="timeline"></div>
     </div>
-    <canvas id="timeline" height="100%" width="100%">
-      Your browser does not support the HTML5 canvas tag.</canvas>
-  </div>
-  <br>
+    <br />
 
-  <div id="currentTime">
-
-  </div>
-  <script type="text/javascript">
-    let lanes = [
-      {
-        keyframesLaneSizePx: 1,
-        selected: false,
-        keyframes: [{
-          ms: 40
+    <div id="currentTime"></div>
+    <script type="text/javascript">
+      let lanes = [
+        {
+          keyframesLaneSizePx: 1,
+          selected: false,
+          keyframes: [
+            {
+              ms: 40
+            },
+            {
+              ms: 3000,
+              selected: false
+            }
+          ]
         },
         {
-          ms: 3000,
-          selected: false
-        }
-        ]
-      }, {
-        selected: false,
-        keyframes: [{
-          ms: 2000
-        }, {
-          ms: 2500
+          selected: false,
+          keyframes: [
+            {
+              ms: 2000
+            },
+            {
+              ms: 2500
+            },
+            {
+              ms: 2600
+            }
+          ]
         },
         {
-          ms: 2600
-        }
-        ]
-      }, {
-        keyframes: [{
-          ms: 1000
-        }, {
-          ms: 1500
-        }, {
-          ms: 2000
-        }
-        ]
-      }, {
-        keyframes: [{
-          ms: 40
-        }, {
-          ms: 3000
-        }
-        ]
-      }, {
-        keyframes: [{
-          ms: 100
-        }, {
-          ms: 3410
-        }, {
-          ms: 2000
-        }
-        ]
-      }, {
-        keyframes: [{
-          ms: 90
-        }, {
-          ms: 100
-        }
-        ]
-      }
-    ];
-
-    let timeline = animationTimeline.initialize({ id: 'timeline', scrollId: 'timeline-scroll-container', sizeId: 'timeline-size-content' }, lanes);
-
-    timeline.on('timeChanged', function (object) {
-      document.getElementById('currentTime').innerHTML = object.ms + 'ms';
-    })
+          keyframes: [
+            {
+              ms: 1000
+            },
+            {
+              ms: 1500
+            },
+            {
+              ms: 2000
+            }
+          ]
+        },
+        {
+          keyframes: [
+            {
+              ms: 40
+            },
+            {
+              ms: 3000
+            }
+          ]
+        },
+        {
+          keyframes: [
+            {
+              ms: 100
+            },
+            {
+              ms: 3410
+            },
+            {
+              ms: 2000
+            }
+          ]
+        },
+        {
+          keyframes: [
+            {
+              ms: 90
+            },
+            {
+              ms: 100
+            }
+          ]
+        },
+        {},
+        {},
+        {},
+        {},
+        {},
+        {}
+      ];
 
-  </script>
-</body>
+      let timeline = animationTimeline.initialize(
+        {
+          id: "timeline"
+        },
+        lanes
+      );
 
-</html>
+      timeline.on("timeChanged", function(object) {
+        document.getElementById("currentTime").innerHTML = object.ms + "ms";
+      });
+    </script>
+  </body>
+</html>