Przeglądaj źródła

move from CoordMap to CoordCache

Adam Shaw 10 lat temu
rodzic
commit
52276bcbf7
3 zmienionych plików z 209 dodań i 164 usunięć
  1. 1 1
      lumbar.json
  2. 208 0
      src/common/CoordCache.js
  3. 0 163
      src/common/CoordMap.js

+ 1 - 1
lumbar.json

@@ -20,7 +20,7 @@
         "src/common/Class.js",
         "src/common/Class.js",
         "src/common/Emitter.js",
         "src/common/Emitter.js",
         "src/common/Popover.js",
         "src/common/Popover.js",
-        "src/common/CoordMap.js",
+        "src/common/CoordCache.js",
         "src/common/DragListener.js",
         "src/common/DragListener.js",
         "src/common/HitDragListener.js",
         "src/common/HitDragListener.js",
         "src/common/MouseFollower.js",
         "src/common/MouseFollower.js",

+ 208 - 0
src/common/CoordCache.js

@@ -0,0 +1,208 @@
+
+/*
+A cache for the left/right/top/bottom/width/height values for one or more elements.
+Works with both offset (from topleft document) and position (from offsetParent).
+
+options:
+- els
+- isHorizontal
+- isVertical
+*/
+var CoordCache = fc.CoordCache = Class.extend({
+
+	els: null, // jQuery set (assumed to be siblings)
+	origin: null, // {left,top} position of offsetParent of els
+	boundingRect: null, // constrain cordinates to this rectangle. {left,right,top,bottom} or null
+	isHorizontal: false, // whether to query for left/right/width
+	isVertical: false, // whether to query for top/bottom/height
+
+	// arrays of coordinates (offsets from topleft of document)
+	lefts: null,
+	rights: null,
+	tops: null,
+	bottoms: null,
+
+
+	constructor: function(options) {
+		this.els = $(options.els);
+		this.isHorizontal = options.isHorizontal;
+		this.isVertical = options.isVertical;
+	},
+
+
+	// Queries the els for coordinates and stores them.
+	// Call this method before using and of the get* methods below.
+	build: function() {
+		this.origin = this.els.eq(0).offsetParent().offset();
+		this.boundingRect = this.queryBoundingRect();
+
+		if (this.isHorizontal) {
+			this.buildElHorizontals();
+		}
+		if (this.isVertical) {
+			this.buildElVerticals();
+		}
+	},
+
+
+	// Destroys all internal data about coordinates, freeing memory
+	clear: function() {
+		this.origin = null;
+		this.boundingRect = null;
+		this.lefts = null;
+		this.rights = null;
+		this.tops = null;
+		this.bottoms = null;
+	},
+
+
+	// Compute and return what the elements' bounding rectangle is, from the user's perspective.
+	// Right now, only returns a rectangle if constrained by an overflow:scroll element.
+	queryBoundingRect: function() {
+		var scrollParentEl = getScrollParent(this.els.eq(0));
+
+		if (!scrollParentEl.is(document)) {
+			return getOuterRect(scrollParentEl);
+		}
+	},
+
+
+	// Populates the left/right internal coordinate arrays
+	buildElHorizontals: function() {
+		var lefts = [];
+		var rights = [];
+
+		this.els.each(function(i, node) {
+			var el = $(node);
+			var left = el.offset().left;
+			var width = el.outerWidth();
+
+			lefts.push(left);
+			rights.push(left + width);
+		});
+
+		this.lefts = lefts;
+		this.rights = rights;
+	},
+
+
+	// Populates the top/bottom internal coordinate arrays
+	buildElVerticals: function() {
+		var tops = [];
+		var bottoms = [];
+
+		this.els.each(function(i, node) {
+			var el = $(node);
+			var top = el.offset().top;
+			var height = el.outerHeight();
+
+			tops.push(top);
+			bottoms.push(top + height);
+		});
+
+		this.tops = tops;
+		this.bottoms = bottoms;
+	},
+
+
+	// Given a left offset (from document left), returns the index of the el that it horizontally intersects.
+	// If no intersection is made, or outside of the boundingRect, returns undefined.
+	getHorizontalIndex: function(leftOffset) {
+		var boundingRect = this.boundingRect;
+		var lefts = this.lefts;
+		var rights = this.rights;
+		var len = lefts.length;
+		var i;
+
+		if (!boundingRect || (leftOffset >= boundingRect.left && leftOffset < boundingRect.right)) {
+			for (i = 0; i < len; i++) {
+				if (leftOffset >= lefts[i] && leftOffset < rights[i]) {
+					return i;
+				}
+			}
+		}
+	},
+
+
+	// Given a top offset (from document top), returns the index of the el that it vertically intersects.
+	// If no intersection is made, or outside of the boundingRect, returns undefined.
+	getVerticalIndex: function(topOffset) {
+		var boundingRect = this.boundingRect;
+		var tops = this.tops;
+		var bottoms = this.bottoms;
+		var len = tops.length;
+		var i;
+
+		if (!boundingRect || (topOffset >= boundingRect.top && topOffset < boundingRect.bottom)) {
+			for (i = 0; i < len; i++) {
+				if (topOffset >= tops[i] && topOffset < bottoms[i]) {
+					return i;
+				}
+			}
+		}
+	},
+
+
+	// Gets the left offset (from document left) of the element at the given index
+	getLeftOffset: function(leftIndex) {
+		return this.lefts[leftIndex];
+	},
+
+
+	// Gets the left position (from offsetParent left) of the element at the given index
+	getLeftPosition: function(leftIndex) {
+		return this.lefts[leftIndex] - this.origin.left;
+	},
+
+
+	// Gets the right offset (from document left) of the element at the given index.
+	// This value is NOT relative to the document's right edge, like the CSS concept of "right" would be.
+	getRightOffset: function(leftIndex) {
+		return this.rights[leftIndex];
+	},
+
+
+	// Gets the right position (from offsetParent left) of the element at the given index.
+	// This value is NOT relative to the offsetParent's right edge, like the CSS concept of "right" would be.
+	getRightPosition: function(leftIndex) {
+		return this.rights[leftIndex] - this.origin.left;
+	},
+
+
+	// Gets the width of the element at the given index
+	getWidth: function(leftIndex) {
+		return this.rights[leftIndex] - this.lefts[leftIndex];
+	},
+
+
+	// Gets the top offset (from document top) of the element at the given index
+	getTopOffset: function(topIndex) {
+		return this.tops[topIndex];
+	},
+
+
+	// Gets the top position (from offsetParent top) of the element at the given position
+	getTopPosition: function(topIndex) {
+		return this.tops[topIndex] - this.origin.top;
+	},
+
+	// Gets the bottom offset (from the document top) of the element at the given index.
+	// This value is NOT relative to the offsetParent's bottom edge, like the CSS concept of "bottom" would be.
+	getBottomOffset: function(topIndex) {
+		return this.bottoms[topIndex];
+	},
+
+
+	// Gets the bottom position (from the offsetParent top) of the element at the given index.
+	// This value is NOT relative to the offsetParent's bottom edge, like the CSS concept of "bottom" would be.
+	getBottomPosition: function(topIndex) {
+		return this.bottoms[topIndex] - this.origin.top;
+	},
+
+
+	// Gets the height of the element at the given index
+	getHeight: function(topIndex) {
+		return this.bottoms[topIndex] - this.tops[topIndex];
+	}
+
+});

+ 0 - 163
src/common/CoordMap.js

@@ -1,163 +0,0 @@
-
-/* A "coordinate map" converts pixel coordinates into an associated cell, which has an associated date
-------------------------------------------------------------------------------------------------------------------------
-Common interface:
-
-	CoordMap.prototype = {
-		build: function() {},
-		getCell: function(x, y) {}
-	};
-
-*/
-
-/* Coordinate map for a grid component
-----------------------------------------------------------------------------------------------------------------------*/
-
-var GridCoordMap = Class.extend({
-
-	grid: null, // reference to the Grid
-	rowCoords: null, // array of {top,bottom} objects
-	colCoords: null, // array of {left,right} objects
-
-	containerEl: null, // container element that all coordinates are constrained to. optionally assigned
-	bounds: null,
-
-
-	constructor: function(grid) {
-		this.grid = grid;
-	},
-
-
-	// Queries the grid for the coordinates of all the cells
-	build: function() {
-		this.grid.build();
-		this.rowCoords = this.grid.computeRowCoords();
-		this.colCoords = this.grid.computeColCoords();
-		this.computeBounds();
-	},
-
-
-	// Clears the coordinates data to free up memory
-	clear: function() {
-		this.grid.clear();
-		this.rowCoords = null;
-		this.colCoords = null;
-	},
-
-
-	// Given a coordinate of the document, gets the associated cell. If no cell is underneath, returns null
-	getCell: function(x, y) {
-		var rowCoords = this.rowCoords;
-		var rowCnt = rowCoords.length;
-		var colCoords = this.colCoords;
-		var colCnt = colCoords.length;
-		var hitRow = null;
-		var hitCol = null;
-		var i, coords;
-		var cell;
-
-		if (this.inBounds(x, y)) {
-
-			for (i = 0; i < rowCnt; i++) {
-				coords = rowCoords[i];
-				if (y >= coords.top && y < coords.bottom) {
-					hitRow = i;
-					break;
-				}
-			}
-
-			for (i = 0; i < colCnt; i++) {
-				coords = colCoords[i];
-				if (x >= coords.left && x < coords.right) {
-					hitCol = i;
-					break;
-				}
-			}
-
-			if (hitRow !== null && hitCol !== null) {
-
-				cell = this.grid.getCell(hitRow, hitCol); // expected to return a fresh object we can modify
-				cell.grid = this.grid; // for CellDragListener's isCellsEqual. dragging between grids
-
-				// make the coordinates available on the cell object
-				$.extend(cell, rowCoords[hitRow], colCoords[hitCol]);
-
-				return cell;
-			}
-		}
-
-		return null;
-	},
-
-
-	// If there is a containerEl, compute the bounds into min/max values
-	computeBounds: function() {
-		this.bounds = this.containerEl ?
-			getClientRect(this.containerEl) : // area within scrollbars
-			null;
-	},
-
-
-	// Determines if the given coordinates are in bounds. If no `containerEl`, always true
-	inBounds: function(x, y) {
-		var bounds = this.bounds;
-
-		if (bounds) {
-			return x >= bounds.left && x < bounds.right && y >= bounds.top && y < bounds.bottom;
-		}
-
-		return true;
-	}
-
-});
-
-
-/* Coordinate map that is a combination of multiple other coordinate maps
-----------------------------------------------------------------------------------------------------------------------*/
-
-var ComboCoordMap = Class.extend({
-
-	coordMaps: null, // an array of CoordMaps
-
-
-	constructor: function(coordMaps) {
-		this.coordMaps = coordMaps;
-	},
-
-
-	// Builds all coordMaps
-	build: function() {
-		var coordMaps = this.coordMaps;
-		var i;
-
-		for (i = 0; i < coordMaps.length; i++) {
-			coordMaps[i].build();
-		}
-	},
-
-
-	// Queries all coordMaps for the cell underneath the given coordinates, returning the first result
-	getCell: function(x, y) {
-		var coordMaps = this.coordMaps;
-		var cell = null;
-		var i;
-
-		for (i = 0; i < coordMaps.length && !cell; i++) {
-			cell = coordMaps[i].getCell(x, y);
-		}
-
-		return cell;
-	},
-
-
-	// Clears all coordMaps
-	clear: function() {
-		var coordMaps = this.coordMaps;
-		var i;
-
-		for (i = 0; i < coordMaps.length; i++) {
-			coordMaps[i].clear();
-		}
-	}
-
-});