ZIM BITS TUTORIAL

<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>ZIM BITS - Snapping Multiple Objects with JavaScript HTML 5 Canvas and CreateJS - Tips, Techniques and Tutorials</title>

<!-- Welcome to ZIM at https://zimjs.com - Code Creativity!              	        -->
<!-- ZIM runs on the HTML Canvas powered by JavaScript and CreateJS https://createjs.com -->
<!-- Founded by Inventor Dan Zen - http://danzen.com - Canadian New Media Award Winner 	-->
<!-- ZIM is free to use. You can donate to help improve ZIM at http://zimjs.com/donate 	-->

<script src="https://zimjs.org/cdn/1.3.4/createjs.js"></script>
<script src="https://zimjs.org/cdn/01/zim_min.js"></script>
<!-- use zimjs.com/distill for minified individual functions! -->

<script src="https://zimjs.com/bits/footer10.js"></script><!-- you will not need this -->

<script>

// SCALING OPTIONS
// scaling can have values as follows with full being the default
// FIT	sets canvas and stage to dimensions and scales to fit inside window size
// FILL	sets canvas and stage to dimensions and scales to fit outside window size
// FULL	sets stage to window size with no scaling
// "tagID"	add canvas to HTML tag of ID - set to dimensions if provided - no scaling

const scaling = FIT; // this will resize to fit inside the screen dimensions
const width = 1000;
const height = 800;
const color = dark; // or any HTML color such as "violet" or "#333333"
const outerColor = light;

new Frame(scaling, width, height, color, outerColor, ready);
function ready() {
	
	// given F (Frame), S (Stage), W (width), H (height)

	// ZIM BITS - Snapping Multiple Objects (2016 - updated 2022)

	// to snap, you drag an object towards a target
	// when you pressup, you check to see if you hit the target
	// if you do, you move the object to the target
	// if you do not, you move the object to its starting position
	// if targets are far apart, you can use hitTestBounds() or Rect or Circle
	// if targets are close, you can use hitTestReg()
	// to see if the object's shape is hitting the registration point of the target
	// that means we want to put the registration point of the target to the center

	// COMPLEX
	// we also may want some logic as to what target is acceptable
	// handle this by setting properties right on the objects or the targets
	// here we will just make sure that the target only has one object
	// so we will set a full property on the target
	// but if we pick up an object that is currently on a target
	// then we need to set that target's full property to false
	// so we need to know which target an object has been placed on
	// and when we pick up the object, we can set it's target's full to false
	// we also have to set the object's target property to null
	// so this is tricky - we need to make this code ourselves with logic!
	// this technique of setting properties on the objects and targets
	// will work for situations where we only want to drag certain objects to certain targets
	// or situations where certain points are provided for different targets, etc.


	// STEPS - DRAG WITHIN BOUNDS

	// 1. make a Tile of objects to drag
	// 2. give objects startX and startY properties
	// 3. make a Tile of targets
	// 4. give targets a full property and set it to false
	// 5. in a mousedown, if the object was on a target, adjust full and target properties
	// 6. in a pressup, loop through targets and do a hitCheckReg() between object and each target
	// 7. if the object hits a target move to the target and set full and target properties
	// 8. if the object hits no targets then move the target back to the startX and startY
	// 9. optional highlight the target if they are eligable for drop - use a pressmove event

	// 1. make a Tile of objects to drag
	const size = 100;
	const rectangles = new Tile(new Rectangle(size, size, light, pink, 10).centerReg(), 1, 3, 0, 40)
		.loc(300,200)
		.drag();

	// 2. give objects startX and startY properties
	rectangles.loop(function (rect) { // do not chain the loop
		rect.startX = rect.x;
		rect.startY = rect.y;
	});

	// 3. make a Tile of targets
	const targets = new Tile(new Rectangle(size, size, tin, tin, 10).centerReg(), 1, 3, 0, 40).loc(700,200).bot();

	// 4. give targets a full property and set it to false
	targets.loop(function (target) {
		target.full = false;
	});

	// 5. in a mousedown, if the object was on a target, adjust full and target properties
	rectangles.on("mousedown", function(e) {
		rectangle = e.target;
		if (rectangle.target) rectangle.target.full = false;
		rectangle.target = null;
	});

	rectangles.on("pressup", function(e) {
		rectangle = e.target;
		const result = targets.loop(function(target, i) {
			// 6. in a pressup, loop through targets and do a hitCheckReg() between object and each target
			if (rectangle.hitTestReg(target) && !target.full) {
				// 7. if the object hits a target move to the target and set full and target properties
				target.full = true;
				rectangle.target = target;
				// be careful - these are in two different containers
				// could have avoided this by leaving both containers at position 0,0
				const point = targets.localToLocal(target.x, target.y, rectangles);
				rectangle.animate({x:point.x, y:point.y}, .1);
				// be careful - we are now done
				// be careful - we cannot put step 9. in an else here
				// be careful - loop() is a function so a return returns from that function
				return "done";
			}
		});
		if (result == "done") return;
		// 8. if the object hits no targets then move the target back to the startX and startY
		rectangle.animate({x:rectangle.startX, y:rectangle.startY}, .3);
	});

	// 9. optional highlight the target if they are eligable for drop - use a pressmove event
	rectangles.on("pressmove", function(e) {
		rectangle = e.target;
		targets.loop(function(target) {
			if (rectangle.hitTestReg(target) && !target.full) {
				target.color = silver;
				target.borderColor = silver;
			} else {
				target.color = tin;
				target.borderColor = tin;
			}
		});
	});

	const docItems = "Frame,Container,Rectangle,drag,hitTestReg,hitTestBounds,animate,loop,pos,centerReg,loop,zog";
	makeFooter(S, W, H, null, docItems); // ZIM BITS footer - you will not need this

} // end of ready

</script>

<meta name="viewport" content="width=device-width, user-scalable=no" />

</head>

<body>
<!-- canvas with id="myCanvas" is made by zim Frame -->
</body>
</html>