JSON based picture gallery with lazyloading

A picture gallery with zoomwall.js (content-focused photo gallery) & echo.js (image lazyloading) production: https://englishextra.github.io/app/picturewall.html // Images by authors at Unsplash & Flickr What is a json based picture gallery with lazyloading How do you make a json based picture gallery with lazyloading? This script and codes were developed by Englishextra on 30 March 2022, Wednesday.

How do I make an json based picture gallery with lazyloading?
  1. JSON based picture gallery with lazyloading Previews
  2. JSON based picture gallery with lazyloading HTML Codes
  3. JSON based picture gallery with lazyloading CSS Codes
  4. JSON based picture gallery with lazyloading JS Codes
JSON based picture gallery with lazyloading Previews

JSON based picture gallery with lazyloading HTML Codes

<!DOCTYPE html>
<html >
<head>
  <meta charset="UTF-8">
  <title>JSON based picture gallery with lazyloading</title>
  
  
  
      <link rel="stylesheet" href="css/style.css">

  
</head>

<body>
  
	<head>
		<meta charset="utf-8" />
		<meta http-equiv="X-UA-Compatible" content="IE=edge" />
		<meta name="HandheldFriendly" content="True" />
		<meta name="MobileOptimized" content="320" />
		<meta name="viewport" content="width=device-width, initial-scale=1" />
		<title>Все иллюстрации</title>
		<style>
			body,a{color:transparent;}body{background-color:#2B2B2B;}img,svg,canvas{display:none;}
			html,
			body {
				height: 100%;
			}
			html {
				font-size: 15px;
				line-height: 20px;
			}
			body {
				font-size: 1.000rem;
				line-height: 1.333rem;
				margin: 0;
			}
		</style>
	</head>
	<body>
		<svg style="position: absolute; width: 0; height: 0; overflow: hidden;" version="1.1" xmlns="http://www.w3.org/2000/svg">
			<defs>
				<symbol id="ui-icon-Back" viewBox="0 0 32 32">
					<title>Back</title>
					<path d="M32,15v2H3.8l12.3,12.3l-1.4,1.4L0,16L14.7,1.3l1.4,1.4L3.8,15H32z"></path>
				</symbol>
				<symbol id="ui-icon-github" viewBox="0 0 32 32">
					<title>github</title>
					<path d="M32,16.4c0,3.5-1,6.6-3.1,9.4s-4.7,4.7-7.9,5.8c-0.4,0.1-0.6,0-0.8-0.1c-0.2-0.2-0.3-0.4-0.3-0.6v-4.4c0-1.3-0.4-2.3-1.1-3c0.8-0.1,1.5-0.2,2.1-0.4c0.6-0.2,1.3-0.4,2-0.8c0.7-0.4,1.2-0.8,1.7-1.4c0.5-0.5,0.8-1.3,1.1-2.2s0.4-2,0.4-3.1c0-1.7-0.5-3.1-1.6-4.3C25.1,10,25,8.6,24.4,7c-0.4-0.1-1,0-1.7,0.2c-0.7,0.3-1.4,0.6-1.9,0.9L20,8.7c-1.3-0.4-2.6-0.5-4-0.5s-2.7,0.2-4,0.5c-0.2-0.2-0.5-0.3-0.9-0.6c-0.4-0.2-0.9-0.5-1.7-0.8S8,6.9,7.6,7C7,8.6,6.9,10,7.4,11.3c-1.1,1.2-1.6,2.6-1.6,4.3c0,1.2,0.1,2.2,0.4,3.1c0.3,0.9,0.6,1.6,1.1,2.2s1,1,1.7,1.4s1.3,0.6,2,0.8c0.6,0.2,1.3,0.3,2.1,0.4c-0.6,0.5-0.9,1.2-1,2.1c-0.3,0.1-0.6,0.2-0.9,0.3C10.8,26,10.4,26,9.9,26S9,25.9,8.6,25.6c-0.5-0.3-0.8-0.7-1.2-1.3c-0.3-0.4-0.6-0.8-1-1.1s-0.8-0.4-1-0.5L5,22.6c-0.3,0-0.5,0-0.6,0.1c-0.1,0.1-0.1,0.1-0.1,0.2s0.1,0.2,0.2,0.3s0.2,0.2,0.3,0.3l0.1,0.1c0.3,0.1,0.6,0.4,0.9,0.8c0.3,0.4,0.5,0.7,0.7,1.1l0.2,0.5c0.2,0.5,0.5,1,0.9,1.3s0.9,0.5,1.4,0.6s1,0.1,1.4,0.1c0.5,0,0.9,0,1.2-0.1l0.5-0.1c0,0.5,0,1.1,0,1.9s0,1.1,0,1.1c0,0.3-0.1,0.5-0.3,0.6c-0.2,0.2-0.5,0.2-0.8,0.1c-3.2-1.1-5.9-3-7.9-5.8S0,19.9,0,16.4c0-2.9,0.7-5.6,2.1-8S5.5,4,8,2.5s5.1-2.1,8-2.1s5.6,0.7,8,2.1s4.4,3.4,5.8,5.8C31.3,10.8,32,13.5,32,16.4z"></path>
				</symbol>
			</defs>
		</svg>
		<div id="container" class="wrapper">
			<div class="title-bar">
				<a class="btn-title-bar back" href="#">
					<svg class="title-bar-icon">
						<use xlink:href="#ui-icon-Back"></use>
					</svg>
				</a>
				<h1 class="btn-title-bar title">All illustrations</h1>
				<a class="btn-title-bar repo" href="https://github.com/englishextra/englishextra.github.io">
					<svg class="title-bar-icon">
						<use xlink:href="#ui-icon-github"></use>
					</svg>
				</a>
			</div>
			<div id="zoomwall" class="zoomwall"></div>
		</div>
	</body>
  
    <script  src="js/index.js"></script>

</body>
</html>

JSON based picture gallery with lazyloading CSS Codes

/*! libs\picturewall\scss\bundle.scss */

/*! @import "englishextra-ui-colors" */

/**
 * englishextra-ui colors
 * use microsoft.com/en-us/design/color
 * localhost/tools/Tinter-Shader/index.html
 * localhost/tools/perfect_colors/
 * localhost/tools/TinyColor/index.html
 * localhost/tools/color-palette-generator/index.html
 * localhost/tools/hexcolortool/index.html
 * localhost/tools/css3-playground/
 */

/* 0073D2
007DD1
5E308F
9C0087
D13636
F23819
FF4141
00AC54
547E71
8C582C
F5630E
FDE000
C3C3C3
D54848
2D7C9A
2F79B6
EF6B50
EB5262
706D6A
60867B
615FC8
744DA5
3087CD */

/* \$(.*?)\: (.*?)\;
\t\t\t\t\t\t\t\t\t\t
$\1
\$(.*?)\: (.*?)\; .bg-\1 { background-color: $\1; } */ /*! @import "englishextra-ui-variables"; */ /*! * modified zoomwall.js v1.1.1 * The MIT License (MIT) * Copyright (c) 2014 Eric Leong * @see {@link https://github.com/ericleong/zoomwall.js} * @see {@link https://github.com/ericleong/zoomwall.js/blob/master/zoomwall.js} * passes jshint */ .zoomwall { font-size: 0; overflow: hidden; } .zoomwall img { display: inline-block; height: 15vw; opacity: 1; vertical-align: top; -webkit-transform-origin: 0% 0%; transform-origin: 0% 0%; -webkit-transition-property: opacity, -webkit-transform; transition-property: opacity, -webkit-transform; transition-property: transform, opacity; transition-property: transform, opacity, -webkit-transform; -webkit-transition-duration: 0.3s; transition-duration: 0.3s; -webkit-transition-timing-function: ease-out; transition-timing-function: ease-out; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; } .zoomwall.lightbox img { -webkit-transition-timing-function: ease-in; transition-timing-function: ease-in; opacity: 0.3; } .zoomwall.lightbox img.active { opacity: 1; } * { -webkit-box-sizing: border-box; box-sizing: border-box; } html, body { height: 100%; } html { font-size: 15px; line-height: 20px; } body { font-size: 1.000rem; line-height: 1.333rem; color: #1F1F1F; overflow-y: auto; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; -webkit-tap-highlight-color: transparent; outline: none; margin: 0; } a { color: inherit; -webkit-tap-highlight-color: transparent; outline: none; } .wrapper { width: 100%; min-height: 100%; background-color: #2B2B2B; } .title-bar { height: 3.200rem; background-color: #1F1F1F; /* text-align: center; */ } .title-bar a:link, .title-bar a:visited { text-decoration: none; color: #FFFFFF; } .title-bar a:hover { color: #F03B4C; } .title-bar-icon { display: block; width: 1.333rem; height: 1.333rem; /* background-color: red; */ } .title-bar-icon > * { fill: #FFFFFF; } .btn-title-bar svg { display: block; } .btn-title-bar { display: block; position: absolute; color: #FFFFFF; } .btn-title-bar.back { top: 0.933rem; left: 0.933rem; } .btn-title-bar.title { font-family: "Roboto", "Source Sans Pro", "Open Sans", "Exo2", "Fira Sans", "Segoe UI", "Segoe WP", "HelveticaNeue", "Roboto", sans-serif; font-weight: 400; font-size: 0.933rem; line-height: 3.200rem; margin: 0; top: 0; left: 50%; margin-right: -50%; -webkit-transform: translate(-50%, 0); transform: translate(-50%, 0); } .btn-title-bar.repo { top: 0.933rem; right: 0.933rem; } /*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL3Njc3MvYnVuZGxlLnNjc3MiLCIuLi9zY3NzL19jb2xvcnMuc2NzcyIsIi4uL3Njc3MvX3ZhcmlhYmxlcy5zY3NzIiwiLi4vc2Nzcy9fem9vbXdhbGwuZml4ZWQuc2NzcyIsIi4uL3Njc3MvX21haW4uc2NzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSx3Q0FBd0M7QUNBeEMsdUNBQXVDO0FBRXZDOzs7Ozs7Ozs7R0FTRztBQUVIOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O1NBc0JTO0FBMEZUOzs7Ozs7SUFNSTtBQ25JSiwyQ0FBMkM7QUNBM0M7Ozs7Ozs7R0FPRztBQUVIO0NBQ0MsYUFBWTtDQUNaLGlCQUFnQixFQUNoQjs7QUFFRDtDQUNDLHNCQUFxQjtDQUNyQixhQUFZO0NBQ1osV0FBVTtDQUNWLG9CQUFtQjtDQUNuQixnQ0FBdUI7U0FBdkIsd0JBQXVCO0NBQ3ZCLHdEQUF1QztDQUF2QyxnREFBdUM7Q0FBdkMsd0NBQXVDO0NBQXZDLDJEQUF1QztDQUN2QyxrQ0FBeUI7U0FBekIsMEJBQXlCO0NBQ3pCLDZDQUFvQztTQUFwQyxxQ0FBb0M7Q0FDcEMsMEJBQWlCO0lBQWpCLHVCQUFpQjtLQUFqQixzQkFBaUI7U0FBakIsa0JBQWlCLEVBQ2pCOztBQUVEO0NBQ0MsNENBQW1DO1NBQW5DLG9DQUFtQztDQUNuQyxhQUFZLEVBQ1o7O0FBRUQ7Q0FDQyxXQUFVLEVBQ1Y7O0FDakNEO0NBQ0MsK0JBQXNCO1NBQXRCLHVCQUFzQixFQUN0Qjs7QUFFRDs7Q0FFQyxhQUFZLEVBQ1o7O0FBRUQ7Q0FDQyxnQkFBZTtDQUNmLGtCQUFpQixFQUNqQjs7QUFFRDtDQUNDLG9CQUFtQjtDQUNuQixzQkFBcUI7Q0FDckIsZUh1QjhCO0NHdEI5QixpQkFBZ0I7Q0FDaEIsMEJBQWlCO0lBQWpCLHVCQUFpQjtLQUFqQixzQkFBaUI7U0FBakIsa0JBQWlCO0NBQ2pCLHlDQUF3QztDQUN4QyxjQUFhO0NBQ2IsVUFBUyxFQUNUOztBQUVEO0NBQ0MsZUFBYztDQUNkLHlDQUF3QztDQUN4QyxjQUFhLEVBQ2I7O0FBRUQ7Q0FDQyxZQUFXO0NBQ1gsaUJBQWdCO0NBQ2hCLDBCSGE2QixFR1o3Qjs7QUFFRDtDQUNDLGlCQUFnQjtDQUNoQiwwQkFBeUI7Q0FDekIseUJBQXlCLEVBQ3pCOztBQUVEOztDQUVDLHNCQUFxQjtDQUNyQixlQUFjLEVBQ2Q7O0FBRUQ7Q0FDQyxlQUFjLEVBQ2Q7O0FBRUQ7Q0FDQyxlQUFjO0NBQ2QsZ0JBQWU7Q0FDZixpQkFBZ0I7Q0FDaEIsNEJBQTRCLEVBQzVCOztBQUVEO0NBQ0MsY0FBYSxFQUNiOztBQUVEO0NBQ0MsZUFBYyxFQUNkOztBQUVEO0NBQ0MsZUFBYztDQUNkLG1CQUFrQjtDQUNsQixlQUFjLEVBQ2Q7O0FBRUQ7Q0FDQyxjQUFhO0NBQ2IsZUFBYyxFQUNkOztBQUVEO0NBQ0MsMElGN0VvSjtDRThFcEosaUJBQWdCO0NBQ2hCLG9CQUFtQjtDQUNuQixzQkFBcUI7Q0FDckIsVUFBUztDQUNULE9BQU07Q0FDTixVQUFTO0NBQ1QsbUJBQWtCO0NBQ2xCLHNDQUE2QjtTQUE3Qiw4QkFBNkIsRUFDN0I7O0FBRUQ7Q0FDQyxjQUFhO0NBQ2IsZ0JBQWUsRUFDZiIsImZpbGUiOiJidW5kbGUuY3NzIn0= */

JSON based picture gallery with lazyloading JS Codes

/*jslint browser: true */
/*jslint node: true */
/*global echo, Headers, loadJsCss,
Promise, zoomwall */
/*property console, split */
/*!
 * safe way to handle console.log
 * @see {@link https://github.com/paulmillr/console-polyfill}
 */
(function(root){
	"use strict";
	if (!root.console) {
		root.console = {};
	}
	var con = root.console;
	var prop;
	var method;
	var dummy = function () {};
	var properties = ["memory"];
	var methods = ("assert,clear,count,debug,dir,dirxml,error,exception,group," +
		"groupCollapsed,groupEnd,info,log,markTimeline,profile,profiles,profileEnd," +
		"show,table,time,timeEnd,timeline,timelineEnd,timeStamp,trace,warn").split(",");
	for (; (prop = properties.pop()); ) {
		if (!con[prop]) {
			con[prop] = {};
		}
	}
	for (; (method = methods.pop()); ) {
		if (!con[method]) {
			con[method] = dummy;
		}
	}
	prop = method = dummy = properties = methods = null;
}("undefined" !== typeof window ? window : this));
/*!
 * modified zoomwall.js v1.1.1
 * The MIT License (MIT)
 * Copyright (c) 2014 Eric Leong
 * added option to specify data attributes for high and low resolution
 * @see {@link https://github.com/ericleong/zoomwall.js}
 * @see {@link https://github.com/ericleong/zoomwall.js/blob/master/zoomwall.js}
 * passes jshint
 */
(function (root, document) {
	"use strict";
	var zoomwall = {
		create: function (blocks, enableKeys, dataAttributeHighresName, dataAttributeLowresName) {
			var _this = this;
			_this.dataAttributeHighresName = dataAttributeHighresName || "highres";
			_this.dataAttributeLowresName = dataAttributeLowresName || "lowres";
			zoomwall.resize(blocks.children);
			blocks.classList.remove("loading");
			blocks.addEventListener("click", function () {
				if (_this.children && _this.children.length > 0) {
					zoomwall.shrink(_this.children[0]);
				}
			});
			for (var i = 0; i < blocks.children.length; i++) {
				blocks.children[i].addEventListener("click", zoomwall.animate);
			}
			if (enableKeys) {
				zoomwall.keys(blocks);
			}
		},
		keys: function (blocks) {
			var keyPager = function (e) {
				if (e.defaultPrevented) {
					return;
				}
				var elem = blocks || document.getElementsByClassName("zoomwall lightbox")[0];
				if (elem) {
					switch (e.keyCode) {
					case 27:
						if (elem.children && elem.children.length > 0) {
							zoomwall.shrink(elem.children[0]);
						}
						e.preventDefault();
						break;
					case 37:
						zoomwall.page(elem, false);
						e.preventDefault();
						break;
					case 39:
						zoomwall.page(elem, true);
						e.preventDefault();
						break;
					}
				}
			};
			document.addEventListener("keydown", keyPager);
			return keyPager;
		},
		resizeRow: function (row, width) {
			if (row && row.length > 1) {
				for (var i in row) {
					if (row.hasOwnProperty(i)) {
						row[i].style.width = (parseInt(window.getComputedStyle(row[i]).width, 10) / width * 100) + "%";
						row[i].style.height = "auto";
					}
				}
			}
		},
		calcRowWidth: function (row) {
			var width = 0;
			for (var i in row) {
				if (row.hasOwnProperty(i)) {
					width += parseInt(window.getComputedStyle(row[i]).width, 10);
				}
			}
			return width;
		},
		resize: function (blocks) {
			var row = [];
			var top = -1;
			for (var c = 0; c < blocks.length; c++) {
				var block = blocks[c];
				if (block) {
					if (top == -1) {
						top = block.offsetTop;
					} else if (block.offsetTop != top) {
						zoomwall.resizeRow(row, zoomwall.calcRowWidth(row));
						row = [];
						top = block.offsetTop;
					}
					row.push(block);
				}
			}
			zoomwall.resizeRow(row, zoomwall.calcRowWidth(row));
		},
		reset: function (block) {
			block.style.transform = "translate(0, 0) scale(1)";
			block.style.webkitTransform = "translate(0, 0) scale(1)";
			block.classList.remove("active");
		},
		shrink: function (block) {
			block.parentNode.classList.remove("lightbox");
			zoomwall.reset(block);
			var prev = block.previousElementSibling;
			while (prev) {
				zoomwall.reset(prev);
				prev = prev.previousElementSibling;
			}
			var next = block.nextElementSibling;
			while (next) {
				zoomwall.reset(next);
				next = next.nextElementSibling;
			}
			if (block.dataset.lowres) {
				block.src = block.dataset.lowres;
			}
		},
		expand: function (block) {
			var _this = this;
			block.classList.add("active");
			block.parentNode.classList.add("lightbox");
			var parentStyle = window.getComputedStyle(block.parentNode);
			var parentWidth = parseInt(parentStyle.width, 10);
			var parentHeight = parseInt(parentStyle.height, 10);
			var parentTop = block.parentNode.getBoundingClientRect().top;
			var blockStyle = window.getComputedStyle(block);
			var blockWidth = parseInt(blockStyle.width, 10);
			var blockHeight = parseInt(blockStyle.height, 10);
			var targetHeight = window.innerHeight;
			if (parentHeight < window.innerHeight) {
				targetHeight = parentHeight;
			} else if (parentTop > 0) {
				targetHeight -= parentTop;
			}
			if (block.dataset[_this.dataAttributeHighresName]) {
				if (block.src != block.dataset[_this.dataAttributeHighresName] && block.dataset[_this.dataAttributeLowresName] === undefined) {
					block.dataset[_this.dataAttributeLowresName] = block.src;
				}
				block.src = block.dataset[_this.dataAttributeHighresName];
			}
			var row = [];
			row.push(block);
			var next = block.nextElementSibling;
			while (next && next.offsetTop == block.offsetTop) {
				row.push(next);
				next = next.nextElementSibling;
			}
			var prev = block.previousElementSibling;
			while (prev && prev.offsetTop == block.offsetTop) {
				row.unshift(prev);
				prev = prev.previousElementSibling;
			}
			var scale = targetHeight / blockHeight;
			if (blockWidth * scale > parentWidth) {
				scale = parentWidth / blockWidth;
			}
			var offsetY = parentTop - block.parentNode.offsetTop + block.offsetTop;
			if (parentHeight < window.innerHeight || blockHeight * scale < parentHeight) {
				offsetY -= targetHeight / 2 - blockHeight * scale / 2;
			}
			if (parentTop > 0) {
				offsetY -= parentTop;
			}
			var leftOffsetX = 0;
			for (var i = 0; i < row.length && row[i] != block; i++) {
				leftOffsetX += parseInt(window.getComputedStyle(row[i]).width, 10) * scale;
			}
			leftOffsetX = parentWidth / 2 - blockWidth * scale / 2 - leftOffsetX;
			var rightOffsetX = 0;
			for (var j = row.length - 1; j >= 0 && row[j] != block; j--) {
				rightOffsetX += parseInt(window.getComputedStyle(row[j]).width, 10) * scale;
			}
			rightOffsetX = parentWidth / 2 - blockWidth * scale / 2 - rightOffsetX;
			var itemOffset = 0;
			var prevWidth = 0;
			for (var k = 0; k < row.length; k++) {
				itemOffset += (prevWidth * scale - prevWidth);
				prevWidth = parseInt(window.getComputedStyle(row[k]).width, 10);
				var percentageOffsetX = (itemOffset + leftOffsetX) / prevWidth * 100;
				var percentageOffsetY = -offsetY / parseInt(window.getComputedStyle(row[k]).height, 10) * 100;
				row[k].style.transformOrigin = "0% 0%";
				row[k].style.webkitTransformOrigin = "0% 0%";
				row[k].style.transform = "translate(" + percentageOffsetX.toFixed(8) + "%, " + percentageOffsetY.toFixed(8) + "%) scale(" + scale.toFixed(8) + ")";
				row[k].style.webkitTransform = "translate(" + percentageOffsetX.toFixed(8) + "%, " + percentageOffsetY.toFixed(8) + "%) scale(" + scale.toFixed(8) + ")";
			}
			var nextOffsetY = blockHeight * (scale - 1) - offsetY;
			var prevHeight;
			itemOffset = 0;
			prevWidth = 0;
			var next2 = row[row.length - 1].nextElementSibling;
			var nextRowTop = -1;
			while (next2) {
				var curTop = next2.offsetTop;
				if (curTop == nextRowTop) {
					itemOffset += prevWidth * scale - prevWidth;
				} else {
					if (nextRowTop != -1) {
						itemOffset = 0;
						nextOffsetY += prevHeight * (scale - 1);
					}
					nextRowTop = curTop;
				}
				prevWidth = parseInt(window.getComputedStyle(next2).width, 10);
				prevHeight = parseInt(window.getComputedStyle(next2).height, 10);
				var percentageOffsetX2 = (itemOffset + leftOffsetX) / prevWidth * 100;
				var percentageOffsetY2 = nextOffsetY / prevHeight * 100;
				next2.style.transformOrigin = "0% 0%";
				next2.style.webkitTransformOrigin = "0% 0%";
				next2.style.transform = "translate(" + percentageOffsetX2.toFixed(8) + "%, " + percentageOffsetY2.toFixed(8) + "%) scale(" + scale.toFixed(8) + ")";
				next2.style.webkitTransform = "translate(" + percentageOffsetX2.toFixed(8) + "%, " + percentageOffsetY2.toFixed(8) + "%) scale(" + scale.toFixed(8) + ")";
				next2 = next2.nextElementSibling;
			}
			var prevOffsetY = -offsetY;
			itemOffset = 0;
			prevWidth = 0;
			var prev2 = row[0].previousElementSibling;
			var prevRowTop = -1;
			while (prev2) {
				var curTop2 = prev2.offsetTop;
				if (curTop2 == prevRowTop) {
					itemOffset -= prevWidth * scale - prevWidth;
				} else {
					itemOffset = 0;
					prevOffsetY -= parseInt(window.getComputedStyle(prev2).height, 10) * (scale - 1);
					prevRowTop = curTop2;
				}
				prevWidth = parseInt(window.getComputedStyle(prev2).width, 10);
				var percentageOffsetX3 = (itemOffset - rightOffsetX) / prevWidth * 100;
				var percentageOffsetY3 = prevOffsetY / parseInt(window.getComputedStyle(prev2).height, 10) * 100;
				prev2.style.transformOrigin = "100% 0%";
				prev2.style.webkitTransformOrigin = "100% 0%";
				prev2.style.transform = "translate(" + percentageOffsetX3.toFixed(8) + "%, " + percentageOffsetY3.toFixed(8) + "%) scale(" + scale.toFixed(8) + ")";
				prev2.style.webkitTransform = "translate(" + percentageOffsetX3.toFixed(8) + "%, " + percentageOffsetY3.toFixed(8) + "%) scale(" + scale.toFixed(8) + ")";
				prev2 = prev2.previousElementSibling;
			}
		},
		animate: function (e) {
			var _this = this;
			if (_this.classList.contains("active")) {
				zoomwall.shrink(_this);
			} else {
				var actives = _this.parentNode.getElementsByClassName("active");
				for (var i = 0; i < actives.length; i++) {
					actives[i].classList.remove("active");
				}
				zoomwall.expand(_this);
			}
			e.stopPropagation();
		},
		page: function (blocks, isNext) {
			var actives = blocks.getElementsByClassName("active");
			if (actives && actives.length > 0) {
				var current = actives[0];
				var next;
				if (isNext) {
					next = current.nextElementSibling;
				} else {
					next = current.previousElementSibling;
				}
				if (next) {
					current.classList.remove("active");
					if (current.dataset.lowres) {
						current.src = current.dataset.lowres;
					}
					zoomwall.expand(next);
				}
			}
		}
	};
	root.zoomwall = zoomwall;
})("undefined" !== typeof window ? window : this, document);
/*!
 * modified Echo.js, simple JavaScript image lazy loading
 * added option to specify data attribute and img class
 * @see {@link https://toddmotto.com/echo-js-simple-javascript-image-lazy-loading/}
 * passes jshint
 */
(function (root, document) {
	"use strict";
	var echo = function (imgClass, dataAttributeName) {
		imgClass = imgClass || "data-src-img";
		dataAttributeName = dataAttributeName || "src";
		var Echo = function (elem) {
			var _this = this;
			_this.elem = elem;
			_this.render();
			_this.listen();
		};
		var isBindedEchoClass = "is-binded-echo";
		var isBindedEcho = (function () {
			return document.documentElement.classList.contains(isBindedEchoClass) || "";
		}
			());
		var echoStore = [];
		var scrolledIntoView = function (element) {
			var coords = element.getBoundingClientRect();
			return ((coords.top >= 0 && coords.left >= 0 && coords.top) <= (window.innerHeight || document.documentElement.clientHeight));
		};
		var echoSrc = function (img, callback) {
			img.src = img.dataset[dataAttributeName] || img.getAttribute("data-" + dataAttributeName);
			if (callback) {
				callback();
			}
		};
		var removeEcho = function (element, index) {
			if (echoStore.indexOf(element) !== -1) {
				echoStore.splice(index, 1);
			}
		};
		var echoImageAll = function () {
			for (var i = 0; i < echoStore.length; i++) {
				var self = echoStore[i];
				if (scrolledIntoView(self)) {
					echoSrc(self, removeEcho(self, i));
				}
			}
		};
		Echo.prototype = {
			init: function () {
				echoStore.push(this.elem);
			},
			render: function () {
				if (document.addEventListener) {}
				else {}
				echoImageAll();
			},
			listen: function () {
				if (!isBindedEcho) {
					root.addEventListener("scroll", echoImageAll);
					document.documentElement.classList.add(isBindedEchoClass);
				}
			}
		};
		var lazyImgs = document.getElementsByClassName(imgClass) || "";
		var walkLazyImageAll = function () {
			for (var i = 0; i < lazyImgs.length; i++) {
				new Echo(lazyImgs[i]).init();
			}
		};
		if (lazyImgs) {
			walkLazyImageAll();
		}
	};
	root.echo = echo;
}
	("undefined" !== typeof window ? window : this, document));
/*!
 * modified loadExt
 * @see {@link https://gist.github.com/englishextra/ff9dc7ab002312568742861cb80865c9}
 * passes jshint
 */
(function (root, document) {
	"use strict";
	var loadJsCss = function (files, callback) {
		var _this = this;
		var getElementsByTagName = "getElementsByTagName";
		var createElement = "createElement";
		var appendChild = "appendChild";
		var body = "body";
		var parentNode = "parentNode";
		var insertBefore = "insertBefore";
		var length = "length";
		_this.files = files;
		_this.js = [];
		_this.head = document[getElementsByTagName]("head")[0] || "";
		_this.body = document[body] || "";
		_this.ref = document[getElementsByTagName]("script")[0] || "";
		_this.callback = callback || function () {};
		_this.loadStyle = function (file) {
			var link = document[createElement]("link");
			link.rel = "stylesheet";
			link.type = "text/css";
			link.href = file;
			_this.head[appendChild](link);
		};
		_this.loadScript = function (i) {
			var script = document[createElement]("script");
			script.type = "text/javascript";
			script.async = true;
			script.src = _this.js[i];
			var loadNextScript = function () {
				if (++i < _this.js[length]) {
					_this.loadScript(i);
				} else {
					_this.callback();
				}
			};
			script.onload = function () {
				loadNextScript();
			};
			_this.head[appendChild](script);
			if (_this.ref[parentNode]) {
				_this.ref[parentNode][insertBefore](script, _this.ref);
			} else {
				(_this.body || _this.head)[appendChild](script);
			}
		};
		var i,
		l;
		for (i = 0, l = _this.files[length]; i < l; i += 1) {
			if ((/\.js$|\.js\?/).test(_this.files[i])) {
				_this.js.push(_this.files[i]);
			}
			if ((/\.css$|\.css\?|\/css\?/).test(_this.files[i])) {
				_this.loadStyle(_this.files[i]);
			}
		}
		i = l = null;
		if (_this.js[length] > 0) {
			_this.loadScript(0);
		} else {
			_this.callback();
		}
	};
	root.loadJsCss = loadJsCss;
}
	("undefined" !== typeof window ? window : this, document));
/*!
 * app logic
 */
(function(root, document){
	"use strict";

	var run = function () {
		var zoomwallGallery = document.getElementById("zoomwall") || "";
		var imgClass = "data-src-img"; // lazyloader finds images using class name
		var jsonHighresKeyName = "highres"; // should be same img data attribute as in json high resolution key name
		var jsonSrcKeyName = "src"; // will be an initial img src from json
		var jsonUrl = "https://englishextra.github.io/app/libs/picturewall/json/zoomwall.json"; // images list
		/* var myHeaders = new Headers();
		fetch(jsonUrl, {
			headers: myHeaders,
			credentials: "same-origin"
		}).then(function (response) {
			if (response.ok) {
				return response.text();
			} else {
				throw new Error("cannot fetch", jsonUrl);
			}
		}).then(function (text) { */
			var generateGallery = new Promise(function (resolve, reject) {
				var jsonObj;
				try {
					jsonObj = 
[{
  "src": "1440x810",
  "highres": "https://englishextra.github.io/app/libs/pwa-englishextra/img/gallery/aids_most_commonly_used_idioms.jpg"
},
{
  "src": "1440x810",
  "highres": "https://englishextra.github.io/app/libs/pwa-englishextra/img/gallery/aids_topics.jpg"
},
{
  "src": "1440x810",
  "highres": "https://englishextra.github.io/app/libs/pwa-englishextra/img/gallery/articles_reading_rules_utf.jpg"
},
{
  "src": "1440x810",
  "highres": "https://englishextra.github.io/app/libs/pwa-englishextra/img/gallery/grammar_alone_by_myself_and_on_my_own.jpg"
},
{
  "src": "1440x810",
  "highres": "https://englishextra.github.io/app/libs/pwa-englishextra/img/gallery/grammar_can_could_be_able_to.jpg"
},
{
  "src": "1440x810",
  "highres": "https://englishextra.github.io/app/libs/pwa-englishextra/img/gallery/grammar_conditionals.jpg"
},
{
  "src": "1440x810",
  "highres": "https://englishextra.github.io/app/libs/pwa-englishextra/img/gallery/grammar_in_at_on.jpg"
},
{
  "src": "1440x810",
  "highres": "https://englishextra.github.io/app/libs/pwa-englishextra/img/gallery/grammar_in_hospital_at_work.jpg"
},
{
  "src": "1440x810",
  "highres": "https://englishextra.github.io/app/libs/pwa-englishextra/img/gallery/grammar_irregular_verbs.jpg"
},
{
  "src": "1440x810",
  "highres": "https://englishextra.github.io/app/libs/pwa-englishextra/img/gallery/grammar_much_many_little_few.jpg"
},
{
  "src": "1440x810",
  "highres": "https://englishextra.github.io/app/libs/pwa-englishextra/img/gallery/grammar_phrasal_verbs.jpg"
},
{
  "src": "1440x810",
  "highres": "https://englishextra.github.io/app/libs/pwa-englishextra/img/gallery/grammar_too_enough_so_such.jpg"
},
{
  "src": "1440x810",
  "highres": "https://englishextra.github.io/app/libs/pwa-englishextra/img/gallery/grammar_usage_of_articles_a_the.jpg"
},
{
  "src": "1440x810",
  "highres": "https://englishextra.github.io/app/libs/pwa-englishextra/img/gallery/grammar_usage_of_tenses.png"
},
{
  "src": "1440x810",
  "highres": "https://englishextra.github.io/app/libs/pwa-englishextra/img/gallery/reading_russia_ukraine_war_conflict_vocabulary.jpg"
},
{
  "src": "1440x810",
  "highres": "https://englishextra.github.io/app/libs/pwa-englishextra/img/gallery/reading_the_man_with_the_scar.jpg"
},
{
  "src": "1440x810",
  "highres": "https://englishextra.github.io/app/libs/pwa-englishextra/img/gallery/tests_common_mistakes_test_advanced.jpg"
},
{
  "src": "1440x810",
  "highres": "https://englishextra.github.io/app/libs/pwa-englishextra/img/gallery/tests_ege_english_test_sample_speaking_1.jpg"
},
{
  "src": "1440x810",
  "highres": "https://englishextra.github.io/app/libs/pwa-englishextra/img/gallery/tests_ege_english_test_sample_speaking_2.jpg"
},
{
  "src": "1440x810",
  "highres": "https://englishextra.github.io/app/libs/pwa-englishextra/img/gallery/tests_ege_english_test_sample_speaking_3.jpg"
},
{
  "src": "1440x810",
  "highres": "https://englishextra.github.io/app/libs/pwa-englishextra/img/gallery/tests_ege_english_test_sample_speaking_4.jpg"
},
{
  "src": "1440x810",
  "highres": "https://englishextra.github.io/app/libs/pwa-englishextra/img/gallery/tests_ege_english_test_sample_speaking_5.jpg"
},
{
  "src": "1440x810",
  "highres": "https://englishextra.github.io/app/libs/pwa-englishextra/img/gallery/tests_ege_english_test_sample_speaking_6.jpg"
},
{
  "src": "1440x810",
  "highres": "https://englishextra.github.io/app/libs/pwa-englishextra/img/gallery/tests_ege_essay_sample.jpg"
},
{
  "src": "1440x810",
  "highres": "https://englishextra.github.io/app/libs/pwa-englishextra/img/gallery/tests_gia_ege_letter_sample.jpg"
},
{
  "src": "1440x810",
  "highres": "https://englishextra.github.io/app/libs/pwa-englishextra/img/gallery/tests_gia_english_test_sample_speaking_1.jpg"
},
{
  "src": "1440x810",
  "highres": "https://englishextra.github.io/app/libs/pwa-englishextra/img/gallery/tests_grammar_tests_with_answers.jpg"
}]
;
					if (!jsonObj[0][jsonHighresKeyName]) {
						throw new Error("incomplete JSON data: no " + jsonHighresKeyName);
					} else {
						if (!jsonObj[0][jsonSrcKeyName]) {
							throw new Error("incomplete JSON data: no " + jsonSrcKeyName);
						}
					}
				} catch (err) {
					console.log("cannot init generateGallery", err);
					return;
				}
				var df = document.createDocumentFragment();
				var key;
				for (key in jsonObj) {
					if (jsonObj.hasOwnProperty(key)) {
						if (jsonObj[key][jsonSrcKeyName] && jsonObj[key][jsonHighresKeyName]) {
							var img = document.createElement("img");
							if ((/^([0-9]+)(\x|\ )([0-9]+)$/).test(jsonObj[key][jsonSrcKeyName])) {
								img.src = ["data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%20",
									jsonObj[key][jsonSrcKeyName].replace("x", "%20"),
									"%27%2F%3E"].join("");
							} else {
								img.src = jsonObj[key][jsonSrcKeyName];
							}
							img.dataset[jsonHighresKeyName] = jsonObj[key][jsonHighresKeyName];
							img.classList.add(imgClass);
							df.appendChild(img);
							df.appendChild(document.createTextNode("\n"));
						}
					}
				}
				key = null;
				/* var i;
				for (i = 0; i < jsonObj.length; i += 1) {
					var img = d.createElement("img");
					img.src = jsonObj[i].src;
					img.dataset[jsonHighresKeyName] = jsonObj[i][jsonHighresKeyName];
					img.classList.add(imgClass);
					df.appendChild(img);
					df.appendChild(d.createTextNode("\n"));
				}
				i = null; */
				if (zoomwallGallery.appendChild(df)) {
					resolve();
				} else {
					reject();
				}
			});
			generateGallery.then(function (result) {
				return result;
			}).then(function (result) {
				var timers = setTimeout(function () {
					clearTimeout(timers);
					timers = null;
					if (zoomwallGallery) {
						zoomwall.create(zoomwallGallery, true, jsonHighresKeyName);
					}
				}, 200);
			}).then(function (result) {
				var timers = setTimeout(function () {
					clearTimeout(timers);
					timers = null;
					echo(imgClass, jsonHighresKeyName);
				}, 200);
			}).catch (function (err) {
				console.log("Cannot create zoomwall gallery", err);
			});
		/* }).catch (function (err) {
			console.log("cannot parse", jsonUrl);
		}); */
		/* var initEcho = function () {
			echo(imgClass, jsonHighresKeyName);
		};
		w.addEventListener("load", initEcho); */
	};

	var scripts = [/* "https://englishextra.github.io/app/libs/picturewall/css/bundle.min.css" */];

	if (!root.Promise) {
		scripts.push("//cdn.jsdelivr.net/es6-promise-polyfill/1.2.0/promise.min.js");
	}

	if (!root.fetch) {
		scripts.push("//cdn.jsdelivr.net/fetch/2.0.1/fetch.min.js");
	}

	/* scripts.push("./js/zoomwall.fixed.min.js", "./js/echo.fixed.js"); */

	var load;
	load = new loadJsCss(scripts, run);
}("undefined" !== typeof window ? window : this, document));
Do you want hide your ip address?Surf anonymously, prevent hackers from acquiring your IP address, send anonymous email, and encrypt your Internet connection. High speed, ultra secure, and easy to use. Instant setup.