ImageGrid/ui/setup.js

440 lines
12 KiB
JavaScript
Raw Normal View History

/**********************************************************************
*
*
**********************************************************************/
// A threshold after which the image block ratio will be changed to
// 'fit-viewer' in single image mode...
//
// NOTE: if null this feature will be disabled.
var PROPORTIONS_RATIO_THRESHOLD = 1.5
/**********************************************************************
* Setup
*/
function setupIndicators(){
showGlobalIndicator(
'single-ribbon-mode',
'Single ribbon mode (F3)')
.css('cursor', 'hand')
.click(function(){ toggleSingleRibbonMode() })
showGlobalIndicator(
'marks-visible',
'Marks visible (F2)')
.css('cursor', 'hand')
.click(function(){ toggleMarkesView() })
showGlobalIndicator(
'marked-only-visible',
'Marked only images visible (shift-F2)')
.css('cursor', 'hand')
.click(function(){ toggleMarkedOnlyView() })
showContextIndicator(
'current-image-marked',
'Image is marked (Ins)')
.css('cursor', 'hand')
.click(function(){ toggleImageMark() })
}
function updateContextIndicators(image){
image = image == null ? getImage() : $(image)
// marked...
var indicator = $('.context-mode-indicators .current-image-marked')
if(image.hasClass('marked')){
indicator.addClass('shown')
} else {
indicator.removeClass('shown')
}
}
// Setup event handlers for data bindings...
//
// This does two jobs:
// - maintain DATA state
// - editor actions
// - focus
// - marking
// - maintain view consistency
// - centering/moving (roll)
// - shifting (expand/contract)
// - zooming (expand/contract)
//
function setupDataBindings(viewer){
viewer = viewer == null ? $('.viewer') : viewer
viewer
.click(function(){
if($('.ribbon').length == 0){
loadDirectoryDialog()
}
})
.on([
'focusingImage',
'fittingImages'
].join(' '),
function(){
updateCurrentMarker()
})
// NOTE: we do not need to worry about explicit centering the ribbon
// here, just ball-park-load the correct batch...
// XXX need to maintain the correct number of images per ribbon
// per zoom setting -- things get really odd when a ribbon
// is smaller than it should be...
// XXX this does not get called on marking...
.on('preCenteringRibbon', function(evt, ribbon, image){
var r = getRibbonIndex(ribbon)
// skip all but the curent ribbon in single image view...
if(toggleSingleImageMode('?') == 'on' && r != getRibbonIndex()){
return
}
var gid = getImageGID(image)
var gr = DATA.ribbons[r]
var img_before = getImageBefore(image, ribbon)
var gid_before = getGIDBefore(gid, r)
var screen_size = getScreenWidthInImages()
screen_size = screen_size < 1 ? 1 : screen_size
var l = ribbon.find('.image').length
// skip the whole thing if the ribbon is not visible -- outside
// of viewer are...
var viewer = $('.viewer')
var H = viewer.height()
var h = getImage().height()
var t = getRelativeVisualPosition(viewer, ribbon).top
// XXX also check for visibility...
if( t+h <= 0 || t >= H ){
return
}
// load images if we do a long jump -- start, end or some mark
// outside of currently loaded section...
if(gid_before == null
|| gid_before != getImageGID(img_before)
// also load if we run out of images in the current ribbon,
// likely due to shifting...
|| ( gr.length > l
&& l < Math.round(screen_size * LOAD_SCREENS))){
loadImagesAround(Math.round(screen_size * LOAD_SCREENS), gid, ribbon)
// roll the ribbon while we are advancing...
} else {
var head = img_before.prevAll('.image')
var tail = img_before.nextAll('.image')
// NOTE: if this is greater than the number of images currently
// loaded, it might lead to odd effects...
var frame_size = Math.ceil((screen_size * LOAD_SCREENS) / 2)
var threshold = Math.floor(frame_size / 2)
threshold = threshold < 1 ? 1 : threshold
// do the loading...
// XXX need to expand/contract the ribbon depending on speed...
// ...might also be a good idea to load smaller images
// while scrolling really fast...
// XXX use extendRibbon, to both roll and expand/contract...
if(tail.length < threshold){
var rolled = rollImages(frame_size, ribbon)
}
if(head.length < threshold){
var rolled = rollImages(-frame_size, ribbon)
}
}
})
.on('shiftedImage', function(evt, image, from, to){
from = getRibbonIndex(from)
//var ribbon = to
to = getRibbonIndex(to)
var gid = getImageGID(image)
var after = getGIDBefore(gid, to)
// remove the elem from the from ribbon...
var index = DATA.ribbons[from].indexOf(gid)
var img = DATA.ribbons[from].splice(index, 1)
// put the elem in the to ribbon...
index = after == null ? 0 : DATA.ribbons[to].indexOf(after) + 1
DATA.ribbons[to].splice(index, 0, gid)
// indicators...
flashIndicator(from < to ? 'next' : 'prev')
})
.on('createdRibbon', function(evt, index){
index = getRibbonIndex(index)
DATA.ribbons.splice(index, 0, [])
})
.on('removedRibbon', function(evt, index){
DATA.ribbons.splice(index, 1)
})
.on('requestedFirstImage', function(evt, ribbon){
var r = getRibbonIndex(ribbon)
var gr = DATA.ribbons[r]
rollImages(-gr.length, ribbon)
})
.on('requestedLastImage', function(evt, ribbon){
var r = getRibbonIndex(ribbon)
var gr = DATA.ribbons[r]
rollImages(gr.length, ribbon)
})
.on('fittingImages', function(evt, n){
// load correct amount of images in each ribbon!!!
var screen_size = getScreenWidthInImages()
var gid = getImageGID()
/* XXX used to skip ribbons that are not visible... (see bellow)
var viewer = $('.viewer')
var H = viewer.height()
var h = getImage().height()
*/
// update and align ribbons...
$('.ribbon').each(function(){
var r = $(this)
/* XXX skip ribbons that are not visible...
* causes misaligns and misloads on zoom-in...
// NOTE: we factor in the scale difference to predict
// ribbon position in the new view...
var t = getRelativeVisualPosition(viewer, r).top * (n/screen_size)
if( t+h <= 0 || t >= H ){
console.log('#### skipping align of ribbon:', getRibbonIndex(r))
return
}
*/
loadImagesAround(Math.round(screen_size * LOAD_SCREENS), gid, r)
})
centerView(null, 'css')
// update settings...
if(toggleSingleImageMode('?') == 'on'){
SETTINGS['single-image-mode-screen-images'] = n
} else {
SETTINGS['ribbon-mode-screen-images'] = n
}
// update proportions...
// XXX for some magical reason this is stable for un-rotated
// images and does mad things for rotate 90/270 images...
// ...the only thing that is
if(window.PROPORTIONS_RATIO_THRESHOLD != null
&& toggleSingleImageMode('?') == 'on'){
var h = getVisibleImageSize('height')
var w = getVisibleImageSize('width')
var H = $('.viewer').innerHeight()
var W = $('.viewer').innerWidth()
var m = Math.min(W/w, H/h)
if(m < PROPORTIONS_RATIO_THRESHOLD){
toggleImageProportions('fit-viewer')
} else {
toggleImageProportions('none')
}
}
// update size classes...
// XXX make thresholds global...
if(n <= 2.5){
$('.viewer')
.removeClass('small')
.addClass('large')
} else if (n >= 6) {
$('.viewer')
.addClass('small')
.removeClass('large')
} else {
$('.viewer')
.removeClass('small')
.removeClass('large')
}
// update previews...
updateImages()
})
.on('focusingImage', function(evt, image){
image = $(image)
DATA.current = getImageGID(image)
if(window.setWindowTitle != null){
// XXX do we need to hide the extension...
setWindowTitle(getImageFileName())
//.split(/\.(jpg|jpeg|png|gif)$/)[0])
}
})
// basic image manipulation...
.on('rotatingLeft rotatingRight', function(evt, image){
$(image).each(function(i, e){
var img = $(this)
var gid = getImageGID(img)
var orientation = img.attr('orientation')
// change the image orientation status and add to
// updated list...
IMAGES[gid].orientation = orientation
if(IMAGES_UPDATED.indexOf(gid) == -1){
IMAGES_UPDATED.push(gid)
}
})
})
.on('flippingVertical flippingHorizontal', function(evt, image){
$(image).each(function(i, e){
var img = $(this)
var gid = getImageGID(img)
var flip = getImageFlipState(img)
IMAGES[gid].flipped = flip
if(IMAGES_UPDATED.indexOf(gid) == -1){
IMAGES_UPDATED.push(gid)
}
})
})
.on('resetToOriginalImage', function(evt, image){
$(image).each(function(i, e){
var img = $(this)
var gid = getImageGID(img)
IMAGES[gid].flipped = null
IMAGES[gid].orientation = 0
if(IMAGES_UPDATED.indexOf(gid) == -1){
IMAGES_UPDATED.push(gid)
}
})
})
// marks...
// XXX toggle marking a block is not yet supported...
.on('togglingMark', function(evt, img, action){
var gid = getImageGID(img)
// add marked image to list...
if(action == 'on'){
MARKED.indexOf(gid) == -1 && MARKED.push(gid)
// remove marked image from list...
} else {
MARKED.splice(MARKED.indexOf(gid), 1)
}
})
.on('removeingRibbonMarks', function(evt, ribbon){
$.each(DATA.ribbons[getRibbonIndex(ribbon)], function(_, e){
var i = MARKED.indexOf(e)
if(i != -1){
MARKED.splice(i, 1)
}
})
})
.on('removeingAllMarks', function(evt){
MARKED.splice(0, MARKED.length)
})
.on('markingRibbon', function(evt, ribbon){
$.each(DATA.ribbons[getRibbonIndex(ribbon)], function(_, e){
var i = MARKED.indexOf(e)
if(i == -1){
MARKED.push(e)
}
})
})
.on('markingAll', function(evt){
MARKED.splice(0, MARKED.length)
MARKED.concat(DATA.order)
})
.on('invertingMarks', function(evt, ribbon){
$.each(DATA.ribbons[getRibbonIndex(ribbon)], function(_, e){
var i = MARKED.indexOf(e)
if(i == -1){
MARKED.push(e)
} else {
MARKED.splice(i, 1)
}
})
})
// caching...
.on('reloadedRibbon updatedRibbon', function(evt, ribbon){
window.DEBUG && console.log('>>> (ribbon:', getRibbonIndex(ribbon), ') Updating cache...')
preCacheRibbonImages(ribbon)
})
// info...
.on('focusingImage',
function(){
showRibbonIndicator()
})
.on([
'focusedNextRibbon',
'focusedPrevRibbon'
].join(' '),
function(){
if(toggleSingleImageMode('?') == 'on'){
flashRibbonIndicator()
}
})
.on([
'focusingImage',
'togglingMark'
].join(' '),
function(evt, image){
image = $(image)
updateGlobalImageInfo(image)
updateContextIndicators(image)
})
.on([
'rotatingLeft',
'rotateingRight',
'flippingVertical',
'flippingHorizontal'
].join(' '),
function(evt, image){
updateGlobalImageInfo($(image))
})
.on([
'removeingAllMarks',
'removeingRibbonMarks',
'markingAll',
'markingRibbon',
'invertingMarks'
].join(' '),
function(){
updateGlobalImageInfo()
updateContextIndicators()
})
.on('baseURLChanged', function(evt, url){
saveLocalStorageBaseURL()
saveLocalStorageBaseURLHistory()
})
}
/**********************************************************************
* vim:set ts=4 sw=4 : */