A library that adds simple PowerPoint like DOM object manipulation: resize, drag, and rotate. Pretty lightweight and comes with (very beautifully) styled controls. This library also provides the means for you to calculate collision via an implementation of oriented bounding boxes.
Run npm i @andynoob/move-it and read on.
Fully functional sample code can be found here.
Please ensure that the moving element is absolutely positioned, relative to the control root. Otherwise, expect the transform controls to be mis-fit around the moving element.
To start, create an instance of Moving by calling createMoveMe (or MoveIt.createMoveMe). For example:
const el = document.querySelector(/* ... */);
const controlRoot = el.parentElement!;
const snapping = {
// omitted... we'll get to this later
};
const moving = createMoveMe(el, {
initialState: { // optional, the code will call computeState on the target (first parameter) if this is absent
x: 200,
y: 200,
width: 200,
height: 120,
rotation: 75,
},
format: {
// when asPercent = true, the x, y, width, and height values is in
// percentages (in decimal) relative to the control root
asPercent: false,
// when centered = true, the RectState represents the pivot of the element (which can be changed
// by `pivotOffset`). this can be used with usePercent. when this is paired with `autoSize`,
// the library will keep the element centered on the pivot point whenever resizing happens
centered: false
},
snappingg, // optional
controlRoott, // required, sets the bounds for the object
// when autoSize = true, the library stops assigning width and height directly via CSS, but rather syncs the
// `RectState` automatically whenever the size changes via DOM `ResizeObserver`.
// this also implicitly disables the resize feature.
autoSize: false,
// percent (expressed as decimal) of each axis to offset the pivot point of the moving element.
// this will impact the rotation pivot, the grid snapping location, and `autoSize` if enabled. the default pivot
// point is the center of the element. to make it top left, do `{x: -0.5, y: -0.5}`. this will affect `centered` states
pivotOffset: {x: 0, y: 0}
});If
initialStateis not present as a part of the option parameter,computeStatewill be called to calculate aRectStatefrom the target element (width, rotation, etc.).
Calling the createMoveMe function will return an instance of the Moving interface:
interface Moving {
element: HTMLElement,
id: string,
/**
* @description a copy of the current `RectState`. in the format option provided in the initial options
*/
getState: () =>gt; RectState,
/**
* @description partial in the format option provided in the options
*/
updateState: (partial: PartialRectState>gt;) =>gt; void,
destroy: () =>gt; void,
render: () =>gt; void,
select: () =>gt; void,
isSelected: () =>gt; boolean,
checkBounds: () =>gt; void,
updateControls: (select: boolean) =>gt; Controls,
getCollisionSiblings: () =>gt; Moving[],
/**
* You need to do this for both instances, the behavior is not mirrored by default
* For example, say you have `instanceA` and `instanceB`, you need to run both
* `instanceA.addCollisionSibling(instanceB)` and `instanceB.addCollisionSibling(instanceA)`
* for both instances to collide with the other.
*/
addCollisionSibling: (sibling: Moving) =>gt; void,
removeCollisionSibling: (sibling: Moving) =>gt; void,
getOptions: () =>gt; MoveMeOpt
} Call destroy when you're done moving the object.
The transform control is added immediately when you call the createMoveMe. As seen in the GIF below, it consists of five lines and five dots.
The CSS for these controls can be found here (the CONTROL_ID is E4UKgq3cxN, contrary to its name, it's actually a class). The style is injected into the ad> tag (if not present), under a