ZIM BITS TUTORIAL

<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>ZIM BITS - Scrollbar with Slider Component</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 - Scrollbar using ZIM Slider (2016 - updated 2022)
	
	// *****************************
	// ******* ALL THIS GOES AWAY WITH ZIM Window() and ZIM List() *********
	// see also ZIM BITS Window example with the Window() class
	// also see ZIM List() in Docs

	// the Slider class can act as a scrollbar setting the inside parameter to true
	// this example shows two different scrollbars styled differently
	// the second one adds damping to the page movement and keyboard functionality
	// in both cases we make the scoll button change to reflect the percentage of content showing


	// STEPS

	// 1. make assets to scroll - put these in a mask
	// 2. make a Button for the scrollbar that will be passed into the slider
	// 3. add a Slider with the inside property set to true
	// 4. capture the change event and scroll the page to the right location

	// with this setting, components will not update the stage - we need to in our event functions!
	OPTIMIZE = true;

	// now a single createjs Ticker is made that will handle stage update
	// we do this for the second example which uses damping which requires continuous update
	Ticker.update = true;

	
	// 1. make assets to scroll - put these in a mask
	let viewerW = 400;
	let viewerH = 300;
	let scrollW = 25;

	const mask = new Rectangle(viewerW,viewerH)
		.addTo()
		.pos(70, 200);

	const page = new Container()
		.addTo()
		.pos(mask.x, mask.y);
	let pageH = viewerH*2;
	const back = new Rectangle(viewerW, pageH, darker)
		.addTo(page);
	const circle = F.makeCircles(viewerW/2*.8)
		.centerReg(page);
	page.setMask(mask);

	// 2. make a Button for the scrollbar that will be passed into the slider
	// width, height, label, color, rollColor, borderColor, borderWidth, corner, shadowColor, shadowBlur, hitPadding
	const button = new Button({
		width:scrollW,
		height:viewerH/pageH*viewerH, // note the proportion of viewable height / total height (then * viewable height)
		label:"",
		color:pink,
		rollColor:green,
		corner:0
	}).expand(); // helps on mobile

	// 3. add a Slider with the inside property set to true
	// min really is the slider start value and max is the slider end value
	// in this case, we want the page to go from 0 to negative the height of the hidden part of the page
	// min and step default to 0 anyway but including them just as a reminder
	// min, max, step, button, barLength, barWidth, barColor, vertical, useTicks, inside
	const scrollbar = new Slider({
		min:0,
		max:pageH-viewerH,
		step:0,
		button:button,
		barLength:viewerH,
		barWidth:scrollW,
		barColor:grey,
		vertical:true,
		keyArrows:false,
		inside:true,
		currentValue:pageH-viewerH
	})
		.addTo()
		.pos(page.x + viewerW, page.y);


	// 4. capture the change event and scroll the page to the right location
	scrollbar.on("change", function() {
		page.y = mask.y + scrollbar.currentValue - scrollbar.max;
		// S.update(); // would normally just update stage here - but we have a Ticker doing this for damping below
	});


	////////////////  SECOND EXAMPLE  //////////////////////////

	viewerW = 300;
	viewerH = 300;
	scrollW = 25;

	const mask2 = new Rectangle(viewerW,viewerH)
		.addTo()
		.pos(600, 200);

	pageH = viewerH*4; // make a longer page this time
	const page2 = new Container()
		.addTo()
		.pos(mask2.x, mask2.y);
	const back2 = new Rectangle(viewerW, pageH, lighter)
		.addTo(page2);
	const s = back2.height/(4);
	let c;
	for (let i=0; i<4; i++) {
		c = F.makeCircles(viewerW/2*.8)
			.loc(viewerW/2, s/2 + s*i, page2);
	}
	page2.setMask(mask2);

	// width, height, label, color, rollColor, borderColor, borderWidth, corner, shadowColor, shadowBlur, hitPadding
	const button2 = new Button({
		width:scrollW,
		height:viewerH/pageH*viewerH, // note the proportion of viewable height / total height (then * viewable height)
		label:"",
		backgroundColor:silver,
		rollBackgroundColor:tin,
		corner:scrollW*.5
	}).expand(); // helps on mobile

	// min, max, step, button, barLength, barWidth, barColor, vertical, useTicks, inside
	const scrollbar2 = new Slider({
		min:0,
		max:pageH-viewerH,
		step:0,
		button:button2,
		barLength:viewerH,
		barWidth:scrollW,
		barColor:light,
		vertical:true,
		inside:true,
		currentValue:pageH-viewerH
	})
		.addTo()
		.pos(page2.x + viewerW, page2.y);

	let desiredY = page2.y;
	const damp = new Damp(desiredY, .1);

	scrollbar2.on("change", doScroll2);
	function doScroll2() {
		desiredY = mask2.y + scrollbar2.currentValue - scrollbar2.max;
	};

	Ticker.add(function() {
		page2.y = damp.convert(desiredY);
	});

	// EXTRA
	// ALL THIS GOES AWAY WHEN USING ZIM Window() and ZIM List()
	// can set the scrollbar position like so:
	// scrollbar2.currentValue = -200;
	// desiredY = mask2.y + scrollbar2.currentValue;
	// damp.immediate(desiredY);
	// doScroll2();

	// below we will use the keyboard commands for the second scroll
	// you could use them for either by adding your own focus variable for the last scrolled
	// see the https://zimjs.com/tabs.html example for the technique

	////////////////  KEYBOARD  //////////////////////////

	F.on("keydown", function(e) {
		const arrowAmount = 20;
		const pageAmount = viewerH*.95;
		if (e.keyCode == 38) { // up
			scrollbar2.currentValue += arrowAmount;
		} else if (e.keyCode == 40) { // down
			scrollbar2.currentValue -= arrowAmount;
		} else if (e.keyCode == 33) { // page up
			scrollbar2.currentValue += pageAmount;
		} else if (e.keyCode == 34) { // page down
			scrollbar2.currentValue -= pageAmount;
		}
		desiredY = mask2.y + scrollbar2.currentValue;
		doScroll2();
	});

	////////////////  SCROLLWHEEL  //////////////////////////

	window.removeEventListener("wheel", F.zil[1]);
	window.removeEventListener("DOMMouseScroll", F.zil[2]);

	function displaywheel(e){
		const wheelAmount = 40;
	    const evt=window.event || e;
		//check for detail first so Opera uses that instead of wheelDelta
	    const delta=evt.detail? evt.detail*(-120) : evt.wheelDelta;
	    //delta returns +120 when wheel is scrolled up, -120 when down
		if (delta > 0) {
			scrollbar2.currentValue += wheelAmount;
		} else {
			scrollbar2.currentValue -= wheelAmount;
		}
		desiredY = mask2.y + scrollbar2.currentValue;
		doScroll2();
	}

	//FF doesn't recognize mousewheel as of FF3.x
	const mousewheelevt=(/Firefox/i.test(navigator.userAgent))? "DOMMouseScroll" : "mousewheel"
	if (document.attachEvent) { //if IE (and Opera depending on user setting)
	    document.attachEvent("on"+mousewheelevt, displaywheel);
	} else if (document.addEventListener) { //WC3 browsers
	    document.addEventListener(mousewheelevt, displaywheel, false);
	}


	// EXTRA EXTRA
	// could add buttons on top and bottom that do what the arrows are doing


	const title = "Scrollbar with Slider Component";
	new Label(title, 30, null, "#666")
		.pos(40, 40);

	const docItems = "Frame,Container,Rectangle,Label,Button,Window,List,Slider,pos,addTo,centerReg,expand,setMask,Damp,zog,OPTIMIZE,Ticker";
	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>