mirror of
				https://github.com/excalidraw/excalidraw.git
				synced 2025-11-03 20:34:40 +01:00 
			
		
		
		
	Add support for forward (#100)
This commit is contained in:
		
				
					committed by
					
						
						GitHub
					
				
			
			
				
	
			
			
			
						parent
						
							e9484080e7
						
					
				
				
					commit
					6b8d2970ac
				
			@@ -1,6 +1,11 @@
 | 
			
		||||
import { moveOneLeft, moveAllLeft } from "./zindex";
 | 
			
		||||
import { moveOneLeft, moveOneRight, moveAllLeft, moveAllRight } from "./zindex";
 | 
			
		||||
 | 
			
		||||
function expectMove(fn, elems, indices, equal) {
 | 
			
		||||
function expectMove<T>(
 | 
			
		||||
  fn: (elements: T[], indicesToMove: number[]) => void,
 | 
			
		||||
  elems: T[],
 | 
			
		||||
  indices: number[],
 | 
			
		||||
  equal: T[]
 | 
			
		||||
) {
 | 
			
		||||
  fn(elems, indices);
 | 
			
		||||
  expect(elems).toEqual(equal);
 | 
			
		||||
}
 | 
			
		||||
@@ -17,6 +22,18 @@ it("should moveOneLeft", () => {
 | 
			
		||||
  expectMove(moveOneLeft, ["a", "b", "c", "d"], [1, 3], ["b", "a", "d", "c"]);
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
it("should moveOneRight", () => {
 | 
			
		||||
  expectMove(moveOneRight, ["a", "b", "c", "d"], [1, 2], ["a", "d", "b", "c"]);
 | 
			
		||||
  expectMove(moveOneRight, ["a", "b", "c", "d"], [3], ["a", "b", "c", "d"]);
 | 
			
		||||
  expectMove(
 | 
			
		||||
    moveOneRight,
 | 
			
		||||
    ["a", "b", "c", "d"],
 | 
			
		||||
    [0, 1, 2, 3],
 | 
			
		||||
    ["a", "b", "c", "d"]
 | 
			
		||||
  );
 | 
			
		||||
  expectMove(moveOneRight, ["a", "b", "c", "d"], [0, 2], ["b", "a", "d", "c"]);
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
it("should moveAllLeft", () => {
 | 
			
		||||
  expectMove(
 | 
			
		||||
    moveAllLeft,
 | 
			
		||||
@@ -49,3 +66,36 @@ it("should moveAllLeft", () => {
 | 
			
		||||
    ["e", "f", "g", "a", "b", "c", "d"]
 | 
			
		||||
  );
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
it("should moveAllRight", () => {
 | 
			
		||||
  expectMove(
 | 
			
		||||
    moveAllRight,
 | 
			
		||||
    ["a", "b", "c", "d", "e", "f", "g"],
 | 
			
		||||
    [2, 5],
 | 
			
		||||
    ["a", "b", "d", "e", "g", "c", "f"]
 | 
			
		||||
  );
 | 
			
		||||
  expectMove(
 | 
			
		||||
    moveAllRight,
 | 
			
		||||
    ["a", "b", "c", "d", "e", "f", "g"],
 | 
			
		||||
    [5],
 | 
			
		||||
    ["a", "b", "c", "d", "e", "g", "f"]
 | 
			
		||||
  );
 | 
			
		||||
  expectMove(
 | 
			
		||||
    moveAllRight,
 | 
			
		||||
    ["a", "b", "c", "d", "e", "f", "g"],
 | 
			
		||||
    [0, 1, 2, 3, 4, 5, 6],
 | 
			
		||||
    ["a", "b", "c", "d", "e", "f", "g"]
 | 
			
		||||
  );
 | 
			
		||||
  expectMove(
 | 
			
		||||
    moveAllRight,
 | 
			
		||||
    ["a", "b", "c", "d", "e", "f", "g"],
 | 
			
		||||
    [0, 1, 2],
 | 
			
		||||
    ["d", "e", "f", "g", "a", "b", "c"]
 | 
			
		||||
  );
 | 
			
		||||
  expectMove(
 | 
			
		||||
    moveAllRight,
 | 
			
		||||
    ["a", "b", "c", "d", "e", "f", "g"],
 | 
			
		||||
    [4, 5, 6],
 | 
			
		||||
    ["a", "b", "c", "d", "e", "f", "g"]
 | 
			
		||||
  );
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -19,6 +19,24 @@ export function moveOneLeft<T>(elements: T[], indicesToMove: number[]) {
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function moveOneRight<T>(elements: T[], indicesToMove: number[]) {
 | 
			
		||||
  const reversedIndicesToMove = indicesToMove.sort(
 | 
			
		||||
    (a: number, b: number) => b - a
 | 
			
		||||
  );
 | 
			
		||||
  let isSorted = true;
 | 
			
		||||
 | 
			
		||||
  // We go from right to left to avoid overriding the wrong elements
 | 
			
		||||
  reversedIndicesToMove.forEach((index, i) => {
 | 
			
		||||
    // We don't want to bubble the first elements that are sorted as they are
 | 
			
		||||
    // already in their correct position
 | 
			
		||||
    isSorted = isSorted && index === elements.length - i - 1;
 | 
			
		||||
    if (isSorted) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    swap(elements, index + 1, index);
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Let's go through an example
 | 
			
		||||
//        |        |
 | 
			
		||||
// [a, b, c, d, e, f, g]
 | 
			
		||||
@@ -95,3 +113,81 @@ export function moveAllLeft<T>(elements: T[], indicesToMove: number[]) {
 | 
			
		||||
    elements[i] = element;
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Let's go through an example
 | 
			
		||||
//        |        |
 | 
			
		||||
// [a, b, c, d, e, f, g]
 | 
			
		||||
// -->
 | 
			
		||||
// [a, b, d, e, g, c, f]
 | 
			
		||||
//
 | 
			
		||||
// We are going to override all the elements we want to move, so we keep them in an array
 | 
			
		||||
// that we will restore at the end.
 | 
			
		||||
// [c, f]
 | 
			
		||||
//
 | 
			
		||||
// From now on, we'll never read those values from the array anymore
 | 
			
		||||
//        |0       |1
 | 
			
		||||
// [a, b, _, d, e, _, g]
 | 
			
		||||
//
 | 
			
		||||
// The idea is that we want to shift all the elements between the marker 0 and 1
 | 
			
		||||
// by one slot to the left.
 | 
			
		||||
//
 | 
			
		||||
//        |0       |1
 | 
			
		||||
// [a, b, _, d, e, _, g]
 | 
			
		||||
//          <- <-
 | 
			
		||||
//
 | 
			
		||||
// which gives us
 | 
			
		||||
//
 | 
			
		||||
//        |0       |1
 | 
			
		||||
// [a, b, d, e, _, _, g]
 | 
			
		||||
//
 | 
			
		||||
// Now, we need to move all the elements from marker 1 to the end by two (not one)
 | 
			
		||||
// slots to the left, which gives us
 | 
			
		||||
//
 | 
			
		||||
//        |0       |1
 | 
			
		||||
// [a, b, d, e, _, _, g]
 | 
			
		||||
//              ^------
 | 
			
		||||
//
 | 
			
		||||
// which gives us
 | 
			
		||||
//
 | 
			
		||||
//        |0       |1
 | 
			
		||||
// [a, b, d, e, g, _, _]
 | 
			
		||||
//
 | 
			
		||||
// At this point, we can fill back the rightmost elements with the array we saved at
 | 
			
		||||
// the beggining
 | 
			
		||||
//
 | 
			
		||||
//        |0       |1
 | 
			
		||||
// [a, b, d, e, g, c, f]
 | 
			
		||||
//
 | 
			
		||||
// And we are done!
 | 
			
		||||
export function moveAllRight<T>(elements: T[], indicesToMove: number[]) {
 | 
			
		||||
  const reversedIndicesToMove = indicesToMove.sort(
 | 
			
		||||
    (a: number, b: number) => b - a
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  // Copy the elements to move
 | 
			
		||||
  const rightMostElements = reversedIndicesToMove.map(index => elements[index]);
 | 
			
		||||
 | 
			
		||||
  indicesToMove = reversedIndicesToMove
 | 
			
		||||
    // We go from left to right to avoid overriding elements.
 | 
			
		||||
    .reverse()
 | 
			
		||||
    // We last element index for the final marker
 | 
			
		||||
    .concat([elements.length]);
 | 
			
		||||
 | 
			
		||||
  indicesToMove.forEach((index, i) => {
 | 
			
		||||
    // We skip the first one as it is not paired with anything else
 | 
			
		||||
    if (i === 0) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // We go from the next marker to the left (i - 1) to the current one (index)
 | 
			
		||||
    for (let pos = indicesToMove[i - 1] + 1; pos < index; ++pos) {
 | 
			
		||||
      // We move by 1 the first time, 2 the second... So we can use the index i in the array
 | 
			
		||||
      elements[pos - i] = elements[pos];
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  // The final step
 | 
			
		||||
  rightMostElements.forEach((element, i) => {
 | 
			
		||||
    elements[elements.length - i - 1] = element;
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user