magnet.js

Magnet.js

Magnet.js is a JavaScript library making HTML elements attractable to each other.


Demo

Basic

Samples of using magnet.js:

Groups

Creates magnet blocks of different groups.

Get Started

:warning: Since v2.0.0, magnet.js has become a HTML element for us to wrap other elements or directly use it as a attractable block.

Add magnet.js to your HTML file:

<script defer src="https://unpkg.com/@lf2com/magnet.js@latest/dist/magnet.min.js"></script>
<!-- or -->
<script defer src="https://cdn.jsdelivr.net/gh/lf2com/magnet.js@latest/dist/magnet.min.js"></script>

We can use magnets directly in HTML:

<magnet-block
  style="width: 100px; height: 50px; background: #fcc;"
  attract-distance="10"
  align-to="outer|center"
>
  foo
</magnet-block>

<magnet-block attract-distance="10" align-to="outer|center">
  <div style="width: 100px; height: 50px; background: #fcc;">
    bar
  </div>
</magnet-block>

Or in JavaScript code:

const magnet = document.createElement('magnet-block');

magnet.setAttribute('attract-distance', '10');
magnet.setAttribute('align-to', 'outer|center');
// or
magnet.attractDistance = 10;
magnet.alignTos = ['outer', 'center'];

magnet.style.setProperty('width', '100px');
magnet.style.setProperty('height', '50px');
magnet.style.setProperty('background', '#fcc');
magnet.innerText = 'foo';
document.body.append(magnet);

Since magnet.js is an element, we can handle it with jQuery:

$('<magnet-block>')
  .attr({
    'attract-distance': '10',
    'align-to': 'outer|center',
  })
  .css({
    width: '100px',
    height: '50px',
    background: '#fcc',
  })
  .html('foo')
  .appendTo($('body'));

Of course we can use it in React:

const Magnet = () => (
  <magnet-block
    style=
    attract-distance="10"
    align-to="outer|center"
  >
    foo
  </magnet-block>
);

Build

Build magnet.js with the command:

npm run build

The built would be at ./dist/magnet.min.js.

Nodes of Magnet.js

There are 2 magnet elements: <magnet-block> and <magnet-pack>.

<magnet-block>

Magnet block can be dragged and attracted by other magnets.

<magnet-block>
  <div style="padding: 1em; background-color: #eee;">
    magnet
  </div>
</magnet-block>

<!-- or directly use <magnet-block> -->
<magnet-block style="padding: 1em; background-color: #eee;">
  magnet
</magnet-block>

<magnet-pack>

Magnet pack is unable to be dragged but it defines the default values for it’s sub magnets. The sub manget blocks would reference to the nearest parent magnet pack for the attribute value if it doesn’t have assigned the corresponding values.

<magnet-pack attract-distance="20">
  <!-- distance of attraction is 10 -->
  <magnet-block attract-distance="10">
    10
  </magnet-block>

  <!-- distance of attraction is 20 -->
  <magnet-block>
    default
  </magnet-block>
</magnet-pack>

Properties

Settable properties are defined as the configuration values of magnet element. If the magnet has no some magnet settings, it would reference to the nearest parent magnet having the value. Otherwise the value would be the default one.

Multiple Values

If a property accepts multiple values. Use any of the following character as separator: |, ,, ;, or space.

.disabled

Type of value: boolean

Default: false

If set, the magnet would be unable to be dragging and attracted.

<!-- disabled magnet -->
<magnet-block disabled>
  magnet
</magnet-block>
// disable magnet
magnet.disabled = true;
// or
magnet.setAttribute('disabled', '');

// get disabled
console.log('Disabled:', magnet.disabled);
// or
console.log('Disabled:', magnet.hasAttribute('disabled'));

.group

Type of value: _string null_

Default: null as ungrouped

The group of magnet element. Once we assign a group for a magnet, it would only attract magnets in the same group. If no group is assigned, the magnet can attract all magnets including grouped ones.

<!-- set group -->
<magnet-block group="alpha">
  alpha
</magnet-block>
<magnet-block group="beta">
  beta
</magnet-block>
<magnet-block>
  ungrouped
</magnet-block>
// set group
magnet.group = 'alpha';
// or
magnet.setAttribute('group', 'alpha');

// get group
console.log('Group:', magnet.group);
// or
console.log('Group:', magnet.getAttribute('group'));

.parentMagnet

Type of value: Magnet

Returns the nearest parent magnet node.

The .parentMagnet of grouped magnet would be the nearest parent magnet in the same group or ungrouped one.

// get parent magnet
console.log('Nearest parent magnet:', magnet.parentMagnet);

.unattractable

Type of value: boolean

Default: false

If set, the magnet would not be attracted.

<!-- set unattractable -->
<magnet-block unattractable>
  magnet
</magnet-block>
// set unattractable
magnet.unattractable = true;
// or
magnet.setAttribute('unattractable', '');

// get unattractable
console.log('Unattractable:', magnet.unattractable);
// or
console.log('Unattractable:', magnet.hasAttribute('unattractable'));

.unmovable

Type of value: boolean

Default: false

If set, the magnet would not be dragged.

<!-- set unmovable -->
<magnet-block unmovable>
  magnet
</magnet-block>
// set unmovable
magnet.unmovable = true;
// or
magnet.setAttribute('unmovable', '');

// get unmovable
console.log('Unmovable:', magnet.unmovable);
// or
console.log('Unmovable:', magnet.hasAttribute('unmovable'));

.attractDistance

Type of value: number

Default: 10

Distance for magnet being dragged to attract other magnets.

We don’t define the distance for magnet to be attracted.

<!-- set distance of attraction -->
<magnet-block attract-distance="20">
  magnet 20
</magnet-block>

<!-- default distance of attraction -->
<magnet-block>
  magnet default
</magnet-block>
// set distance of attraction
magnet.attractDistance = 20;
// or
magnet.setAttribute('attract-distance', '20');

// get distance of attracion in number
console.log('Attraction distance:', magnet.attractDistance);
// or in string
console.log('Attraction distance:', magnet.getAttribute('attract-distance'));

.alignTos

Type of value: string[]

Default: ['outer', 'center', 'extend']

Accepts multiple values.

Sides of rectangle that can be converted to alignments for magnet aligning to other magnets:

Name Description
outer Align to the outer sides of target
inner Align to the inner sides of target
center Align to the center lines of target
extend Align to extended line of assigned alignment including outer, inner and center
<!-- set align to -->
<magnet-block align-to="outer|extend">
  magnet
</magnet-block>
// set align to
magnet.alignTos = ['outer', 'extend'];
// or
magnet.alignTos = 'outer|extend';
// oe
magnet.setAttribute('align-to', 'outer|extend');

// get align-to in array
console.log('Align to:', magnet.alignTos);
// or in string
console.log('Align to:', magnet.getAttribute('align-to'));

.alignToParents

Type of value: string[]

Default: []

Accepts multiple values.

Sides of rectangle that can be converted to alignments for magnet aligning to it’s parent element.

Name Description
inner Align to the inner sides of target
center Align to the center lines of target
<!-- set align to parent -->
<magnet-block align-to-parent="inner|center">
  magnet
</magnet-block>
// set align to parent
magnet.alignToParents = ['inner', 'center'];
// or
magnet.alignToParents = 'inner|center';
// oe
magnet.setAttribute('align-to-parent', 'inner|center');

// get align-to-parent in array
console.log('Align to parent:', magnet.alignToParents);
// or in string
console.log('Align to parent:', magnet.getAttribute('align-to-parent'));

.alignments

Type of value: string[]

Returns the side-to-side alignments from magnet to other magnets. The values are converted from .alignTos.

Name Align to Description
topToTop inner Source top to target top
topToBottom outer Source top to target bottom
rightToRight inner Source right to target right
rightToLeft outer Source right to target left
bottomToTop outer Source bottom to target top
bottomToBottom inner Source bottom to target bottom
leftToRight outer Source left to target right
leftToLeft inner Source left to target left
xCenterToXCenter center The center of source left and right to the center of target left and right
yCenterToYCenter center The center of source top and bottom to the center of target top and bottom
// get alignments
console.log('Alignments:', magnet.alignments);

.parentAlignments

Type of value: string[]

Returns the side-to-side alignments from magnet to it’s parent element. The values are converted from .alignToParents.

// get alignments to parent
console.log('Alignments to parent:', magnet.parentAlignments);

.crossPrevents

Type of value: string[]

Default: []

Accepts multiple values.

Prevents magnet from crossing specific targets such as parent:

Name Description
parent The parent element of magnet
<!-- set cross prevent -->
<magnet-block cross-prevent="parent">
  magnet
</magnet-block>
// set cross prevent
magnet.crossPrevents = ['parent'];
// or
magnet.crossPrevents = 'parent';
// or
magnet.setAttribute('cross-prevent', 'parent');

// get cross-prevent in array
console.log('Cross prevent:', magnet.crossPrevents);
// or in string
console.log('Cross prevent:', magnet.getAttribute('cross-prevent'));

.magnetRect

Returns temporarily created rectangle of magnet.

.magnetRect would not be updated util calling .resetMagnetRect

// get rectangle
console.log('Magnet rect:', magnet.magnetRect);

.parentPack

Returns temporarily created pack of the parent element of magnet.

.parentPack would not be updated util calling .resetParentPack

const parentPack = magnet.parentPack;

// get parent element
console.log('Parent element:', parentPack.raw);
// get parent rectangle
console.log('Parent rect:', parentPack.rect);

.targetMagnetPacks

Returns temporarily created packs of attractable magnets.

.targetMagnetPacks would not be updated util calling .resetTargetMagnetPacks

// get target magnet packs
console.log('Attractable magnet packs:', magnet.targetMagnetPacks);

.lastMagnetOffset

Returns the last offset in point of magnet.

const { x, y } = magnet.lastMagnetOffset;

// get last offset
console.log(`Last offset: (${x}, ${y})`);

.bestAttraction

Returns the best attraction in the last attraction.

const { x, y } = magnet.bestAttraction;

// get best attraction result
console.log('Best attraction on x-axis:', x);
console.log('Best attraction on y-axis:', y);

Methods

Magnet methods handle stuffs related to magnet such as alignment, distance, attraction, and position.

Static

Magnet.getAlignmentsFromAlignTo(alignTo)

Argument Type Description
alignTo string | string[] Value(s) of sides to align

Returns the array of alignments converted from alignTo values.

// get alignments of align-to
console.log('Alignments:', Magnet.getAlignmentsFromAlignTo('inner'));

// get alignments of align-tos
console.log('Alignments:', Magnet.getAlignmentsFromAlignTo(['outer', 'inner']));

Magnet.getMagnetAttractionOffset(attraction)

Argument Type Description
attraction Attraction Result of magnet attraction

Returns the offset in point from attraction result.

Instance

.traceMagnetAttributeValue(attrName)

Argument Type Description
attrName string Attribute name

Returns the value of specific attribute name of magnet. If the magnet doesn’t have the value, it would reference to the nearest parent magnet having the value. Or return null rather than global default value.

// get group
const group = magnet.traceMagnetAttributeValue('group');
// equals to (due to the default value is `null` too)
const group = magnet.group;
<!-- custom attribute -->
<magnet-pack some-attr="some-value">
  <magnet-block id="magnet">
    magnet
  </magnet-block>
</magnet-pack>

<script>
  const magnet = document.getElementById('magnet');

  // trace the custom attribute
  magnet.traceMagnetAttributeValue('some-attr'); // 'some-value'
</script>

.resetMagnetRect()

Removes the temporarily created rectangle of the magnet.

.resetparentPack()

Removes the temporarily created pack of the magnet parent element.

.resetTargetMagnetPacks()

Removes the temporarily created packs of the magnet attractable targets.

.getOtherMagnets()

Returns all other magnet nodes except magnet packs and the magnet caller.

.getAttractableMagnets()

Returns all magnet elements attractable to the magnet caller.

Consideration:

Property Description
disabled Should be false
unattractable Should be false
group Should be seen as attractable group magnet as the magnet caller

.judgeMagnetDistance(distance, options?)

Argument Type Description
distance Distance Result of distance from distance.source to distance.target on distance.alignment
options? object Options for judgement

Returns true if distance passes the judgement.

This method would be called for judging distance result on any method related to attraction.

Properties of options:

Name Type Description
attractDistance? number Distance of attraction. (Default .attractDistance)
alignTos? AlignTo The target alignment sides. (Default .alignTos)

.judgeMagnetDistanceInParent(distance, options?)

The same as .judgeMagnetDistance but also consider a wrapper as the parent.

Properties of options:

Name Type Description
parent? Pack | Rectable | null Wrapper as the parent. If parent is null or undefined, it would be default as .parentPack
onJudgeDistance? .judgeMagnetDistance Function for judging the distance result. (Default .judgeMagnetDistance)

.judgeMagnetAttraction(attraction)

Argument Type Description
attraction Attraction Result of attraction from attraction.source to attraction.target

Returns true if attraction passes the judgement.

.judgeMagnetMovement(pack)

Argument Type Description
pack Pack Pack with the next movement as pack.rect for pack.raw

Returns true if the movement of pack passes the judgement.

.rawDistanceTo(target, alignment)

Argument Type Description
target Rectable | Pack Target for calculating the distance from magnet caller
alignment Alignment Alignment of distance

Returns the value of distance from magnet caller to target on specific alignment.

.distanceTo(target, alignment)

Argument Type Description
target Rectable | Pack Target for calculating the distance from magnet caller
alignment Alignment Alignment of distance

Returns the result of distance from magnet caller to target on specific alignment.

.attractionTo(target, options?)

Argument Type Description
target Rectable | Pack Target for calculating the attraction from magnet caller
options? object Options for attraction

Returns the result of attraction from magnet caller to target.

Properties of options:

Name Type Description
attractDistance? number Distance of attraction. (Default .attractDistance)
alignTos? AlignTo Target alignment sides. (Default .alignTos)
alignments? Alignment Alignments of attraction. (Default Magnet.getAlignmentsFromAlignTo(alignTos))
onJudgeDistance? .judgeMagnetDistance Function for judging the distance result. (Default .judgeMagnetDistance)

.attractionToParent(options?)

The same as .attractionTo but target is the parent of magnet caller.

Different default values of options:

Name Default Value
alignTos .alignToParents

.multiAttractionsTo(targets, options?)

Argument Type Description
targets (Rectable | Pack)[] Targets for calculating the attraction from magnet caller
options? object Options for attraction

Returns the results of attractions from magnet caller to targets.

The properties of options extends that of .attractionTo:

Name Type Description
alignToParents? AlignToParent[] Target alignment sides to the parent of magnet caller. (Default .alignToParents)
attractionBest? AttractionBest Initial result of attraction joining the comparison of other attraction results
onJudgeAttraction? .judgeMagnetAttraction Function for judging the attraction result. (Default .judgeMagnetAttraction)

.getMagnetAttractionResultOfPosition(position, options?)

Argument Type Description
position Point Target position for magnet caller to move to
options? object Options for attraction

Returns the result of final position and attraction after considering position and options:

Name Type Description
position Point | null Final position of magnet caller. If the movement doesn’t pass the judgement, the value would be null
attractionBest AttractionBest | null Attraction result. If the attraction doesn’t pass the judgement, the value would be null

Properties of options:

| Name | Type | Description | | -: | :-: | :- | | ignoreEvent? | boolean | Set true to ignore dispatching attraction related events to magnets. (Default true only if magnet caller is HTMLElement) | | unattractable? | boolean | Set true to disallow attraction but consider options.crossPrevents. (Default .unattractable) | | attractDistance? | number | Distance of attraction. (Default .attractDistance) | | alignTos? | AlignTo | Target alignment sides. (Default .alignTos) | | alignments? | Alignment | Alignments of attraction. (Default the alignments converted from alignTos) | | alignToParents? | AlignToParent[] | Target alignment sides to the parent of magnet caller. (Default .alignToParents) | | crossPrevents? | CrossPrevent[] | Prevent from crossing specific objectives. (Default .crossPrevents](#crossprevents))_ | | parentPack? | _[Pack](#pack)_ | Parent of magnet caller. _(Default [.parentPack](#parentpack))_ | | lastAttractionBest? | _[AttractionBest](#attractionbest)_ | Reference result of attraction for [attraction related events](#events) | | onJudgeDistance? | [.judgeMagnetDistance](#judgemagnetdistancedistance) | Function for judging the distance result. _(Default [.judgeMagnetDistance](#judgemagnetdistancedistance))_ | | onJudgeDistanceInParent? | [.judgeMagnetDistanceInParent](#judgemagnetdistanceinparentdistance-options) | Function for judging the distance result to the parent of magnet caller. _(Default [.judgeMagnetDistanceInParent](#judgemagnetdistanceinparentdistance-options))_ | | onJudgeAttraction? | [.judgeMagnetAttraction](#judgemagnetattractionattraction) | Function for judging the attraction result. _(Default [.judgeMagnetAttraction](#judgemagnetattractionattraction))_ | | onJudgeMovement? | [.judgeMagnetMovement](#judgemagnetmovementpack) | Function for judging the movement result. _(Default [.judgeMagnetAttraction`) |

.getMagnetAttractionResultOfPosition(x, y, options?)

Argument Type Description
x number Value on x-axis
y number Value on y-axis
options? object Options for attraction

The same as .getMagnetAttractionResultOfPosition(point, options?) but the input is (x, y).

.resetMagnetOffset()

Resets the offset of magnet to (0, 0).

.setMagnetOffset(dx, dy)

Argument Type Description
dx number Offset value on x-axis
dy number Offset value on y-axis

Sets the offset of magnet to (dx, dy).

.setMagnetOffset(offset)

Argument Type Description
offset Point Offset of magnet

The same as .setMagnetOffset but the input is Point.

.setMagnetPosition(x, y)

Argument Type Description
x number Value on x-axis
y number Value on y-axis

Sets the position of magnet to (x, y) without any judgement.

.setMagnetPosition(point)

Argument Type Description
point Point Position of magnet

The same as .setMagnetPosition but the input is Point.

Events

Events for magnet elements.

magnetstart

Cancelable: true

Magnet would not be dragged if the event is canceled.

Dispatches on starting to drag a magnet.

Properties of event.detail:

Name Type Description
source Pack Current magnet info
targets Pack[] Attractable magnets
startPoint Point The start point of dragging

magnetmove

Cancelable: true

Magnet would not move at that step if the event is canceled.

Dispatches on dragging a magnet.

Properties of event.detail extend those of magnetstart:

Name Type Description
movePoint Point The move point of dragging

magnetend

Cancelable: false

Dispatches on the end of dragging a magnet.

attract

Cancelable: true

The magnet would not attract the target magnet if the event is canceled.

Dispatches on the magnet attracting other magnet.

Properties of event.detail:

Name Type Description
source Pack Current magnet info
nextRect Rect The rectangle of magnet after attracting
attraction Attraction Attraction result from source to targets

attracted

Cancelable: false

Dispatches on the magnet being attracted by other magnet.

Properties of event.detail:

Name Type Description
source Pack The info of magnet attracting target
target Pack the info of magnet being attracted by source
sourceNextRect Rect The rectangle of source after attracting
distance Distance Distance detail from source to target

attractmove

Cancelable: false

Dispatches on the magnet already attracting a magnet and still on moving.

Properties of event.detail are the same as attract.

attractedmove

Cancelable: false

Dispatches on the magnet being attracted by other magnet and it’s still on moving.

Properties of event.detail are the same as attract.

unattract

Cancelable: false

Dispatches on the magnet unattracting a magnet.

Properties of event.detail are the same as attract.

unattracted

Cancelable: false

Dispatches on the magnet being unattracted by other magnet.

Properties of event.detail:

Name Type Description
source Pack The info of magnet attracting target
target Pack the info of magnet being attracted by source
sourceNextRect Rect The rectangle of source after attracting

Types

Rectable

Defines objects that are able to be converted to rectangle:

Point

Uses DOMPoint as the type of point (x, y).

Properties of point:

Name Type Description
x number Value on x-axis
y number Value on y-axis

Rectangle

Uses DOMRect as the type of rectangle.

Properties of rectangle:

Name Type Description
top number Value on y-axis. Always greater than or equal to bottom
right number Value on x-axis. Always greater than or equal to left
bottom number Value on y-axis. Always lesser than or equal to top
right number Value on x-axis. Always lesser than or equal to right
x number The same as left
y number The same as top
width number Value of right minuses left
height number Value of bottom minuses top

Pack

Wraps the source and its rectangle.

new Pack(source, rect?)

rect represents the rectangle of source since the rectangle may not be the same as the current one of source.

If rect is undefined, source must be rectable so that the rect could be generated from source.

Properties of pack object:

Name Type Description
raw any Returns source
rect Rectangle Returns rect of the stage on creation. Default is the rectangle based on source

Distance

Wraps the info from source to target.

Properties of distance object:

Name Type Description
source Pack Source info
target Pack Target info
alignment Alignment Alignment from source to target
rawDistance number Distance from source to target
absDistance number Absolute distance from source to target

Attraction

Wraps the result(s) of source attracting to target(s).

Properties of attraction object:

Name Type Description
source Pack Source info
target Pack | Pack[] Target info for .attractionTo. Targets infos in array for .multiAttractionsTo
results Distance[] Distance results from source to target on alignments
best AttractionBest The best attraction result

AttractionBest

Wraps the best distance results on axes of x and y.

Properties of best attraction object:

Name Type Description
x? Distance The best result on x-axis
y? Distance The best result on y-axis

License

MIT Copyright @ Wan Wan