Edit in JSFiddle


              
<head>
	<title>Picture Organiser — Shiny Demos</title>
	<meta charset="utf-8">
	<meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0">
	<link rel="stylesheet" href="styles/screen.css">
	<link rel="stylesheet" href="/styles/panel.css">

</head>
<body>

	<img src="https://raw.githubusercontent.com/github-adi/shinydemos/master/demos/picture-organizer/images/1.jpg" alt="Image 1">
	<img src="https://raw.githubusercontent.com/github-adi/shinydemos/master/demos/picture-organizer/images/2.jpg" alt="Image 2">
	<img src="https://raw.githubusercontent.com/github-adi/shinydemos/master/demos/picture-organizer/images/3.jpg" alt="Image 3">
	<img src="https://raw.githubusercontent.com/github-adi/shinydemos/master/demos/picture-organizer/images/4.jpg" alt="Image 4">
	<script src="/scripts/modernizr.js"></script>
	<script src="/scripts/panel.js"></script>
	<script src="scripts/options.js"></script>
	<script src="scripts/script.js"></script>



<script>
function gestureHandler(element) {
	// define a data structure to store our touchpoints in
	this.coords = function(x,y) {
		this.x = x;
		this.y = y;
	};
	this.element = element;
	this.store = [];
	this.store[0] = new this.coords(-1,-1);
	this.store[1] = new this.coords(-1,-1);
	this.dx = 0;
	this.dy = 0;
	this.angle = 0;
	this.size = 0.5;
	var that = this;
	this.element.addEventListener('touchstart', function(e) { e.preventDefault(); e.stopPropagation(); that.init(); that.gesture(e); }, true);
		this.element.addEventListener('touchmove', function(e) { e.preventDefault(); e.stopPropagation(); that.gesture(e); }, true);
	
	this.init = function() {
		// reset stored values
		this.store[0].x = this.store[0].y = this.store[1].x = this.store[1].y = -1;
		// naive way of working out highest z-index?
		var zIndex = 0; // just using positive indices
		var images = document.getElementsByTagName('img');
		for (var i = 0; i<images.length; i++) {
			if (parseInt(images[i].style.zIndex,10) >= zIndex) {
				zIndex = parseInt(images[i].style.zIndex,10) + 1;
			}
		}
		this.element.style.zIndex = zIndex;
	};

	this.gesture = function(e) {
		var x1 = 0;
		var x2 = 0;
		var y1 = 0;
		var y2 = 0;
		var i = 0;
		var angle = 0;
		var size = 0;
		if (e.targetTouches) {
			if (e.targetTouches.length>=2) {
				
				// two (or more) fingers
				x1=e.targetTouches[0].pageX-e.target.offsetLeft;
				y1=e.targetTouches[0].pageY-e.target.offsetTop;
				x2=e.targetTouches[1].pageX-e.target.offsetLeft;
				y2=e.targetTouches[1].pageY-e.target.offsetTop;
				if (this.store[0].x!=-1) {
					angle = Math.atan((y2-y1)/(x2-x1)) - Math.atan((this.store[1].y-this.store[0].y)/(this.store[1].x-this.store[0].x));
					if (Math.abs(angle)>=3) { // jumped 180 degrees due to my poor math skills
						angle = angle-Math.PI;
					}
					size = Math.sqrt(Math.pow((x1-x2),2)+Math.pow((y1-y2),2)) - Math.sqrt(Math.pow((this.store[0].x-this.store[1].x),2)+Math.pow((this.store[0].y-this.store[1].y),2));
					this.twofinger(size,angle);
				}
				// store the values for later comparison
				this.store[0].x = x1;
				this.store[0].y = y1;
				this.store[1].x = x2;
				this.store[1].y = y2;
				
			} else if (e.targetTouches.length == 1) {

				// one finger
				x1=e.targetTouches[0].pageX;
				y1=e.targetTouches[0].pageY;
				// check if user went from two fingers to one finger - otherwise movement offset is wrong depending on which finger was lifted
				if (this.store[1].x!=-1) {
					// treat the two-to-one change as a completely new gesture
					this.init();
				}
				if (this.store[0].x!=-1) {
					this.onefinger(x1-this.store[0].x,y1-this.store[0].y);
				}
				// store the values for later comparison
				this.store[0].x = x1;
				this.store[0].y = y1;
			}
		}
	};
		this.twofinger = function(size,angle) {
		var that = this;
		var size_ratio = ((that.element.width*that.size)+size)/(that.element.width*that.size);
		that.size *= size_ratio;
		if (that.size < 0.5) { that.size = 0.5; }
		if (that.size > 1) { that.size = 1; }
		that.angle += angle;
		that.element.style.OTransform = that.element.style.MozTransform = that.element.style.webkitTransform = that.element.style.transform = 'rotate('+that.angle+'rad) scale('+that.size+')';
	};
	
	this.onefinger = function(dx,dy) {
		var that = this;
		that.element.style.left = that.element.offsetLeft+dx+'px';
		that.element.style.top = that.element.offsetTop+dy+'px';
	};

}

window.addEventListener('load',function() {
	var images = document.getElementsByTagName('img');
	for (var i = 0; i<images.length; i++) {
		// attach the handler
		var gh = new gestureHandler(images[i]);
		// randomise the position
		images[i].style.left = Math.random()*(window.innerWidth-images[i].clientWidth)+'px';
		images[i].style.top = Math.random()*(window.innerHeight-images[i].clientHeight)+'px';
		images[i].style.zIndex = i;
	}
	window.addEventListener('touchmove',function(e) { e.preventDefault(); },false);
	/* known (intentional) issue: this last statement prevents scrolling, so on small screen devices the SD panel will be cut off and non-scrollable */
}, false);

</script>
<style>
@viewport {
	/* belt-and-braces - using viewport meta AND viewport CSS */
	/* width: device-width;
	height: device-height;
	zoom: 1;
	min-zoom: 1;
	max-zoom: 1;
	user-zoom: fixed;
	orientation: landscape;
	resolution: device; */
}
html { background: url(../images/inflicted.png); } /* "Inflicted" Subtle Pattern by Hugo Loning CC BY 3.0 Unported http://subtlepatterns.com/?p=658 */
html,body { min-height: 100%; width: 100%; height: 100%; margin: 0; padding: 0; overflow: hidden; }
img {
	display: block;
	position: absolute;
	z-index:1;
	-o-transform: scale(0.5);
	-moz-transform: scale(0.5);
	-ms-transform: scale(0.5);
	-webkit-transform: scale(0.5);
	transform: scale(0.5);
	top: 0px; left: 0px; /* though this won't be flush, due to transform (actual top and left = half the width/height of image */
	border: 20px transparent solid;
	background-color: #eee;
	background-origin: border-box;
	background-image: url(../images/centermarks.png), url(../images/centermarks.png), url(../images/centermarks.png), url(../images/centermarks.png), url(../images/bullseye.png), url(../images/bullseye.png), url(../images/bullseye.png), url(../images/bullseye.png), url(../images/bullseye.png), url(../images/bullseye.png), url(../images/bullseye.png), url(../images/bullseye.png), url(../images/colourbar.png);
	background-repeat: no-repeat;
	background-position: center bottom, center top, left center, right center, 0 15%,  0 85%,  100% 15%,  100% 85%, 15% 0, 85% 0, 15% 100%, 85% 100%, 100% 70%;
	margin: 0; padding: 0;
}
</style>
</body>