mirror of
				https://github.com/flynx/ImageGrid.git
				synced 2025-11-02 20:30:09 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			350 lines
		
	
	
		
			8.4 KiB
		
	
	
	
		
			JavaScript
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			350 lines
		
	
	
		
			8.4 KiB
		
	
	
	
		
			JavaScript
		
	
	
		
			Executable File
		
	
	
	
	
/**********************************************************************
 | 
						|
* 
 | 
						|
*
 | 
						|
*
 | 
						|
**********************************************************************/
 | 
						|
 | 
						|
// A stub image, also here for documentation...
 | 
						|
var STUB_IMAGE_DATA = {
 | 
						|
	// Entity GID...
 | 
						|
	id: 'STUB-GID',
 | 
						|
 | 
						|
	// Entity type
 | 
						|
	//
 | 
						|
	// can be:
 | 
						|
	// 	- 'image'
 | 
						|
	// 	- 'group'
 | 
						|
	type: 'image',
 | 
						|
 | 
						|
	// Entity state
 | 
						|
	//
 | 
						|
	// can be:
 | 
						|
	// 	- 'single'
 | 
						|
	// 	- 'grouped'
 | 
						|
	// 	- 'hidden'
 | 
						|
	// 	- ...
 | 
						|
	state: 'single',
 | 
						|
 | 
						|
	// Creation time...
 | 
						|
	ctime: 0,
 | 
						|
 | 
						|
	// Original path...
 | 
						|
	path: './images/sizes/900px/SIZE.jpg',
 | 
						|
 | 
						|
	// Previews...
 | 
						|
	// NOTE: the actual values depend on specific image and can be
 | 
						|
	// 		any size...
 | 
						|
	preview: {
 | 
						|
		'150px': './images/sizes/150px/SIZE.jpg',
 | 
						|
		'350px': './images/sizes/350px/SIZE.jpg',
 | 
						|
		'900px': './images/sizes/900px/SIZE.jpg',
 | 
						|
	},
 | 
						|
 | 
						|
	// Classes
 | 
						|
	// XXX currently unused...
 | 
						|
	classes: '',
 | 
						|
 | 
						|
	// Image orientation (optional)
 | 
						|
	//
 | 
						|
	// can be:
 | 
						|
	// 	- null/undefined	- same as 0
 | 
						|
	// 	- 0 (default)		- load as-is
 | 
						|
	// 	- 90				- rotate 90deg CW
 | 
						|
	// 	- 180				- rotate 180deg CW
 | 
						|
	// 	- 270				- rotate 270deg CW (90deg CCW)
 | 
						|
	//
 | 
						|
	// NOTE: use orientationExif2ImageGrid(..) to convert from EXIF 
 | 
						|
	// 		orientation format to ImageGrid format...
 | 
						|
	orientation: 0,
 | 
						|
 | 
						|
	// Image flip state (optional)
 | 
						|
	//
 | 
						|
	// can be:
 | 
						|
	// 	- null/undefined
 | 
						|
	// 	- array
 | 
						|
	//
 | 
						|
	// can contain:
 | 
						|
	// 	- 'vertical'
 | 
						|
	// 	- 'horizontal'
 | 
						|
	//
 | 
						|
	// NOTE: use orientationExif2ImageGrid(..) to convert from EXIF 
 | 
						|
	// 		orientation format to ImageGrid format...
 | 
						|
	flipped: null,
 | 
						|
 | 
						|
	// Image comment (optional)
 | 
						|
	//
 | 
						|
	// can be:
 | 
						|
	// 	- null/undefined
 | 
						|
	// 	- string
 | 
						|
	comment: null,
 | 
						|
 | 
						|
	// List of image tags (optional)
 | 
						|
	//
 | 
						|
	// can be:
 | 
						|
	// 	- null/undefined
 | 
						|
	// 	- array
 | 
						|
	tags: null,
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
// List of function that update image state...
 | 
						|
//
 | 
						|
// these are called by updateImage(..) after the image is created.
 | 
						|
//
 | 
						|
// each function must be of the form:
 | 
						|
// 	updateImage(gid, image) -> image
 | 
						|
//
 | 
						|
var IMAGE_UPDATERS = []
 | 
						|
 | 
						|
 | 
						|
 | 
						|
/*********************************************************************/
 | 
						|
 | 
						|
// XXX Constructors...
 | 
						|
 | 
						|
 | 
						|
/*********************************************************************/
 | 
						|
 | 
						|
// Run all the image update functions registered in IMAGE_UPDATERS, on 
 | 
						|
// an image...
 | 
						|
//
 | 
						|
function updateImageIndicators(gid, image){
 | 
						|
	gid = gid == null ? getImageGID() : gid
 | 
						|
	image = image == null ? getImage() : $(image)
 | 
						|
 | 
						|
	IMAGE_UPDATERS.forEach(function(update){
 | 
						|
		update(gid, image)
 | 
						|
	})
 | 
						|
 | 
						|
	return image
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
// helper...
 | 
						|
function _loadImagePreviewURL(image, url){
 | 
						|
	// pre-cache and load image...
 | 
						|
	// NOTE: this will make images load without a blackout...
 | 
						|
	var img = new Image()
 | 
						|
	img.onload = function(){
 | 
						|
		image.css({
 | 
						|
				'background-image': 'url("'+ url +'")',
 | 
						|
			})
 | 
						|
	}
 | 
						|
	img.src = url
 | 
						|
	return img
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
// Update an image element
 | 
						|
//
 | 
						|
// NOTE: care must be taken to reset ALL attributes an image can have,
 | 
						|
// 		a common bug if this is not done correctly, is that some settings
 | 
						|
// 		may leak to newly loaded images...
 | 
						|
function updateImage(image, gid, size, sync){
 | 
						|
	image = image == null ? getImage() : $(image)
 | 
						|
	sync = sync == null ? CONFIG.load_img_sync : sync
 | 
						|
	var old_gid = getImageGID(image)
 | 
						|
 | 
						|
	// same image -- update...
 | 
						|
	if(old_gid == gid || gid == null){
 | 
						|
		gid = old_gid
 | 
						|
 | 
						|
	// reuse for different image -- reconstruct...
 | 
						|
	} else {
 | 
						|
		// remove old marks...
 | 
						|
		if(typeof(old_gid) == typeof('str')){
 | 
						|
			getImageMarks(old_gid).remove()
 | 
						|
		}
 | 
						|
		// reset gid...
 | 
						|
		image
 | 
						|
			.attr('gid', JSON.stringify(gid))
 | 
						|
			.css({
 | 
						|
				// clear the old preview...
 | 
						|
				'background-image': '',
 | 
						|
			})
 | 
						|
	}
 | 
						|
	size = size == null ? getVisibleImageSize('max') : size
 | 
						|
 | 
						|
	// get the image data...
 | 
						|
	var img_data = IMAGES[gid]
 | 
						|
	if(img_data == null){
 | 
						|
		img_data = STUB_IMAGE_DATA
 | 
						|
	}
 | 
						|
 | 
						|
	/* XXX does not seem to be needing this...
 | 
						|
	// set the current class...
 | 
						|
	if(gid == DATA.current){
 | 
						|
		image.addClass('current')
 | 
						|
	} else {
 | 
						|
		image.removeClass('current')
 | 
						|
	}
 | 
						|
	*/
 | 
						|
 | 
						|
	// preview...
 | 
						|
	var p_url = getBestPreview(gid, size).url
 | 
						|
 | 
						|
	// update the preview if it's a new image or...
 | 
						|
	if(old_gid != gid 
 | 
						|
			// the new preview (purl) is different to current...
 | 
						|
			|| image.css('background-image').indexOf(encodeURI(p_url)) < 0){
 | 
						|
		// sync load...
 | 
						|
		if(sync){
 | 
						|
			_loadImagePreviewURL(image, p_url)
 | 
						|
 | 
						|
		// async load...
 | 
						|
		} else {
 | 
						|
			// NOTE: storing the url in .data() makes the image load the 
 | 
						|
			// 		last requested preview and in a case when we manage to 
 | 
						|
			// 		call updateImage(...) on the same element multiple times 
 | 
						|
			// 		before the previews get loaded...
 | 
						|
			// 		...setting the data().loading is sync while loading an 
 | 
						|
			// 		image is not, and if several loads are done in sequence
 | 
						|
			// 		there is no guarantee that they will happen in the same
 | 
						|
			// 		order as requested...
 | 
						|
			image.data().loading = p_url
 | 
						|
			setTimeout(function(){ 
 | 
						|
				_loadImagePreviewURL(image, image.data().loading)
 | 
						|
			}, 0)
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	// main attrs...
 | 
						|
	image
 | 
						|
		.attr({
 | 
						|
			order: DATA.order.indexOf(gid),
 | 
						|
			orientation: img_data.orientation == null ? 0 : img_data.orientation,
 | 
						|
		})
 | 
						|
 | 
						|
	// flip...
 | 
						|
	setImageFlipState(image, img_data.flipped == null ? [] : img_data.flipped)
 | 
						|
 | 
						|
	// NOTE: this only has effect on non-square image blocks...
 | 
						|
	correctImageProportionsForRotation(image)
 | 
						|
 | 
						|
	// marks and other indicators...
 | 
						|
	updateImageIndicators(gid, image)
 | 
						|
 | 
						|
	return image
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
// Same as updateImage(...) but will update all loaded images.
 | 
						|
//
 | 
						|
// If list is passed this will update only the images in the list. The
 | 
						|
// list can contain either gids or image elements.
 | 
						|
//
 | 
						|
// If CONFIG.update_sort_enabled is set, this will prioritize images by
 | 
						|
// distance from current image, loading the closest images first...
 | 
						|
//
 | 
						|
// If CONFIG.update_sync is set, this will run asynchronously.
 | 
						|
function updateImages(list, size, cmp){
 | 
						|
	var deferred = $.Deferred()
 | 
						|
 | 
						|
	function _worker(){
 | 
						|
		list = list == null ? $('.image') : $(list)
 | 
						|
		size = size == null ? getVisibleImageSize('max') : size
 | 
						|
 | 
						|
		function _update(_, e){
 | 
						|
			var img = typeof(e) == typeof('str') ? getImage(e) : $(e)
 | 
						|
			if(img.length > 0){
 | 
						|
				updateImage(img, null, size)
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		// sorted run...
 | 
						|
		if(CONFIG.update_sort_enabled && cmp != false){
 | 
						|
			cmp = cmp == null ? 
 | 
						|
					makeGIDDistanceCmp(getImageGID(), function(e){ 
 | 
						|
						return typeof(e) == typeof('str') ? e : getImageGID(e) 
 | 
						|
					}) 
 | 
						|
					// XXX this is more correct but is slow...
 | 
						|
					//makeGIDRibbonDistanceCmp(getImageGID(), getImageGID) 
 | 
						|
				: cmp
 | 
						|
			deferred.resolve(list
 | 
						|
				// sort images by distance from current, so as to update what 
 | 
						|
				// the user is looking at first...
 | 
						|
				.sort(cmp)
 | 
						|
				.map(_update))
 | 
						|
 | 
						|
		// do a fast run w.o. sorting images...
 | 
						|
		} else {
 | 
						|
			deferred.resolve(list.map(_update))
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if(CONFIG.update_sync){
 | 
						|
		_worker()
 | 
						|
	} else {
 | 
						|
		setTimeout(_worker, 0)
 | 
						|
	}
 | 
						|
 | 
						|
	return deferred
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
// Compensate for viewer proportioned and rotated images.
 | 
						|
//
 | 
						|
// This will set the margins so as to make the rotated image offset the
 | 
						|
// same space as it is occupying visually...
 | 
						|
//
 | 
						|
// NOTE: this is not needed for square image blocks.
 | 
						|
// NOTE: if an image block is square, this will remove the margins.
 | 
						|
function correctImageProportionsForRotation(images, container){
 | 
						|
	container = container == null ? $('.viewer') : container
 | 
						|
 | 
						|
	var W = container.innerWidth()
 | 
						|
	var H = container.innerHeight()
 | 
						|
 | 
						|
	var viewer_p = W > H ? 'landscape' : 'portrait'
 | 
						|
 | 
						|
	return $(images).each(function(i, e){
 | 
						|
		var image = $(this)
 | 
						|
		// orientation...
 | 
						|
		var o = image.attr('orientation')
 | 
						|
		o = o == null ? 0 : o
 | 
						|
		var w = image.outerWidth()
 | 
						|
		var h = image.outerHeight()
 | 
						|
 | 
						|
		// non-square image...
 | 
						|
		if(w != h){
 | 
						|
 | 
						|
			var image_p = w > h ? 'landscape' : 'portrait'
 | 
						|
 | 
						|
			// when the image is turned 90deg/270deg and its 
 | 
						|
			// proportions are the same as the screen...
 | 
						|
			if((o == 90 || o == 270) && image_p == viewer_p){
 | 
						|
				image.css({
 | 
						|
					width: h,
 | 
						|
					height: w,
 | 
						|
				})
 | 
						|
				image.css({
 | 
						|
					'margin-top': -((w - h)/2),
 | 
						|
					'margin-bottom': -((w - h)/2),
 | 
						|
					'margin-left': (w - h)/2,
 | 
						|
					'margin-right': (w - h)/2,
 | 
						|
				})
 | 
						|
 | 
						|
			} else if((o == 0 || o == 180) && image_p != viewer_p){
 | 
						|
				image.css({
 | 
						|
					width: h,
 | 
						|
					height: w,
 | 
						|
				})
 | 
						|
				image.css({
 | 
						|
					'margin': '',
 | 
						|
				})
 | 
						|
			}
 | 
						|
 | 
						|
		// square image...
 | 
						|
		} else {
 | 
						|
			image.css({
 | 
						|
				'margin': '',
 | 
						|
			})
 | 
						|
		}
 | 
						|
	})
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
/**********************************************************************
 | 
						|
* vim:set ts=4 sw=4 :                                                */
 |