experimenting...

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2017-07-29 21:39:47 +03:00
parent 6f8ef29f2e
commit 831e82a28a
6 changed files with 434 additions and 112 deletions

View File

@ -19,6 +19,7 @@
border-bottom: solid 5px red; border-bottom: solid 5px red;
} }
.mark,
.image { .image {
position: relative; position: relative;
display: inline-block; display: inline-block;
@ -28,14 +29,37 @@
outline: solid 1px blue; outline: solid 1px blue;
background: silver; background: silver;
vertical-align: middle;
}
.image:after {
content: attr(gid);
} }
.current.image { .current.image {
background: gray; background: gray;
} }
.mark { .mark {
position: absolute; margin-left: -100px;
background: none;
pointer-events: none;
} }
.mark:after {
position: absolute;
content: "";
top: 0;
right: 0;
width: 0;
height: 0;
border: solid 10px red;
border-bottom-color: transparent;
border-left-color: transparent;
pointer-events: auto;
}
</style> </style>
@ -63,7 +87,7 @@ var stub_data = {
order: [].slice.call('abcdefghijklmopqrstuvwxyz'), order: [].slice.call('abcdefghijklmopqrstuvwxyz'),
tags: { tags: {
a: [].slice.call('ahdtu'), selected: [].slice.call('ahdtu'),
b: [].slice.call('adxz'), b: [].slice.call('adxz'),
}, },
@ -109,11 +133,23 @@ class IGRibbon extends preact.Component {
var data = props.data var data = props.data
var ribbon = props.gid var ribbon = props.gid
var images = data.ribbons[ribbon].map(function(gid){ var images = data.ribbons[ribbon]
return h(IGImage, { .map(function(gid){
gid: gid, var marks = data.tags.selected.indexOf(gid) >= 0 ?
data: data h(IGImageMark, {
})}) gid: gid,
type: 'selected',
data: data,
})
: []
return [
h(IGImage, {
gid: gid,
data: data,
})].concat(marks)
})
.reduce(function(a, b){ return a.concat(b) })
.filter(function(a){ return !!a })
var base = data.base == ribbon ? ['base'] : [] var base = data.base == ribbon ? ['base'] : []
@ -146,14 +182,22 @@ class IGImage extends preact.Component {
// XXX background-image... // XXX background-image...
}, },
// XXX experiemnt... // XXX STUB
onClick: function(evt){ onClick: function(evt){
// toggle tag...
if(data.current == gid){
var selected = data.tags.selected = data.tags.selected || []
selected.indexOf(gid) < 0 ?
selected.push(gid)
: selected.splice(selected.indexOf(gid), 1)
}
// set current...
data.current = gid data.current = gid
render() render()
} },
}, [ })
gid
])
} }
} }
@ -161,10 +205,22 @@ class IGImage extends preact.Component {
// - image mark // - image mark
class IGImageMark extends preact.Component { class IGImageMark extends preact.Component {
render(props, state){ render(props, state){
var gid = props.gid
var type = props.type
var data = props.data
return h('div', return h('div',
{ {
classList: ['mark'], classList: ['mark'].concat([type]).join(' '),
gid: props.gid, gid: gid,
// XXX STUB...
// ...and there is no way to add the mark back...
onClick: function(evt){
data.tags[type].splice(data.tags[type].indexOf(gid), 1)
render()
},
}) })
} }
} }

View File

@ -26,13 +26,26 @@ var ribbons = require('imagegrid/ribbons')
/*********************************************************************/ /*********************************************************************/
var RibbonsClassPrototype = { var RibbonsClassPrototype = {
// This is needed to calculate image size when no images are loaded...
createImage: function(){
// XXX
},
// XXX // XXX
} }
RibbonsClassPrototype.__proto__ = ribbons.BaseRibbons.prototype.__proto__ RibbonsClassPrototype.__proto__ = ribbons.BaseRibbons.prototype.__proto__
var RibbonsPrototype = { var RibbonsPrototype = {
viewer: null,
createImage: RibbonsClassPrototype.createImage,
// XXX // XXX
__init__: function(viewer, images){
// XXX
},
} }
RibbonsPrototype.__proto__ = ribbons.BaseRibbons.prototype RibbonsPrototype.__proto__ = ribbons.BaseRibbons.prototype
@ -77,14 +90,36 @@ var RenderActions = actions.Actions({
}], }],
reload: [ reload: [
function(){ function(){
// full reload...
if(force == 'full'){
//this.stop()
/*
killAllWorkers()
.done(function(){
reload()
})
*/
return location.reload()
}
if(!this.ribbons){
return
}
// XXX // XXX
}], }],
refresh: [ refresh: [
function(){ function(){
if(!this.ribbons){
return
}
// XXX // XXX
}], }],
clear: [ clear: [
function(){ function(){
if(!this.ribbons){
return
}
// XXX // XXX
}], }],
@ -106,6 +141,9 @@ var RenderActions = actions.Actions({
viewScale: ['- Zoom/', viewScale: ['- Zoom/',
function(scale){ function(scale){
if(!this.ribbons){
return
}
if(scale == null || scale == '?'){ if(scale == null || scale == '?'){
return // XXX get scale... return // XXX get scale...
} }
@ -116,22 +154,43 @@ var RenderActions = actions.Actions({
}], }],
fitImage: ['Zoom/Fit image', fitImage: ['Zoom/Fit image',
function(count, overflow){ function(count, overflow){
if(!this.ribbons){
return
}
if(count == '?'){ if(count == '?'){
return // XXX get size... return // XXX get size...
} }
this.resizing.chainCall(this, function(){ this.resizing.chainCall(this, function(){
if(count != null){
overflow = overflow == false ? 0 : overflow
var o = overflow != null ? overflow
: count % 2 != 1 ? 0
: (this.config['fit-overflow'] || 0)
count += o
}
// set the scale...
// XXX
// refresh image previews...
// XXX // XXX
}, 'screenwidth', count, overflow) }, 'screenwidth', count, overflow)
}], }],
fitRibbon: ['Zoom/Fit ribbon vertically', fitRibbon: ['Zoom/Fit ribbon vertically',
function(count, whole){ function(count, whole){
if(!this.ribbons){
return
}
if(count == '?'){ if(count == '?'){
return // XXX get size... return // XXX get size...
} }
this.resizing.chainCall(this, function(){ this.resizing.chainCall(this, function(){
// XXX set size... // XXX set size...
// XXX refresh image previews...
}, 'screenheight', count, whole) }, 'screenheight', count, whole)
}], }],
@ -139,15 +198,24 @@ var RenderActions = actions.Actions({
centerImage: ['- Interface/Center an image in ribbon horizontally', centerImage: ['- Interface/Center an image in ribbon horizontally',
function(target, align, offset, scale){ function(target, align, offset, scale){
if(!this.ribbons){
return
}
// XXX // XXX
}], }],
centerRibbon: ['- Interface/Center a ribbon vertically', centerRibbon: ['- Interface/Center a ribbon vertically',
function(target){ function(target){
if(!this.ribbons){
return
}
// XXX // XXX
}], }],
ribbonRotation: ['- Interface|Ribbon/', ribbonRotation: ['- Interface|Ribbon/',
function(angle){ function(angle){
if(!this.ribbons){
return
}
// XXX // XXX
}], }],
}) })

View File

@ -37,33 +37,28 @@ var ribbons = require('imagegrid/ribbons')
// - do we update preview in Preact render or outside? // - do we update preview in Preact render or outside?
// //
// render:
// - ribbon-set
// - ribbon-locator
// - current-indicator (???)
//
// * this is static and only created once...
class IGRibbonSet extends preact.Component { class IGRibbonSet extends preact.Component {
render(props, state){ render(props, state){
var data = props.data
// XXX need: var ribbons = data.ribbon_order.map(function(gid){
// - scale return h(IGRibbon, {
// - ribbons gid: gid,
current: data.current,
var ribbons = data.ribbon_order base: data.base,
.map(function(gid){ return h(IGRibbon, { data: data
ribbon: gid,
// XXX
}) }) }) })
var s = props.scale || 1
return h('div.ribbon-set', return h('div',
{ {
className: 'ribbon-set',
style: { style: {
transform: 'scale('+ s +', '+ s +')', transform: 'scale('+ s +', '+ s +')',
}, },
}, [ }, [
h('div.current-marker'), h('div', {className: 'current-marker'}),
h('div.ribbon-locator', null, ribbons), h('div', {className: 'ribbon-locator'}, ribbons),
]) ])
} }
} }
@ -72,8 +67,42 @@ class IGRibbonSet extends preact.Component {
// - ribbon // - ribbon
// - images // - images
// - image marks // - image marks
//
// XXX needs horizontal align...
class IGRibbon extends preact.Component { class IGRibbon extends preact.Component {
render(props, state){ render(props, state){
var data = props.data
var ribbon = props.gid
var images = data.ribbons[ribbon]
.map(function(gid){
var marks = data.tags.selected.indexOf(gid) >= 0 ?
h(IGImageMark, {
gid: gid,
type: 'selected',
data: data,
})
: []
return [
h(IGImage, {
gid: gid,
data: data,
})].concat(marks)
})
.reduce(function(a, b){ return a.concat(b) })
.filter(function(a){ return !!a })
var base = data.base == ribbon ? ['base'] : []
return h('div',
{
classList: ['ribbon'].concat(base).join(' '),
gid: props.gid,
style: {
// XXX offset...
},
}, images)
} }
} }
@ -81,6 +110,21 @@ class IGRibbon extends preact.Component {
// - image // - image
class IGImage extends preact.Component { class IGImage extends preact.Component {
render(props, state){ render(props, state){
var data = props.data || {}
var gid = props.gid
return h('div',
{
classList: ['image']
.concat(data.current == gid ? ['current'] : [])
.join(' '),
gid: gid || '',
style: {
// XXX background-image...
},
// XXX handle clicks???
})
} }
} }
@ -88,6 +132,15 @@ class IGImage extends preact.Component {
// - image mark // - image mark
class IGImageMark extends preact.Component { class IGImageMark extends preact.Component {
render(props, state){ render(props, state){
var gid = props.gid
var type = props.type
var data = props.data
return h('div',
{
classList: ['mark'].concat([type]).join(' '),
gid: gid,
})
} }
} }
@ -96,13 +149,45 @@ class IGImageMark extends preact.Component {
//--------------------------------------------------------------------- //---------------------------------------------------------------------
var RibbonsClassPrototype = { var RibbonsClassPrototype = {
// XXX // XXX this is almost exclusively needed for determining scale...
createImage: function(){
return preact.render(h(IGImage)) },
} }
RibbonsClassPrototype.__proto__ = ribbons.BaseRibbons.prototype.__proto__ RibbonsClassPrototype.__proto__ = ribbons.BaseRibbons.prototype.__proto__
var RibbonsPrototype = { var RibbonsPrototype = {
// XXX viewer: null,
dom: null,
createImage: RibbonsClassPrototype.createImage,
update: function(data, full){
if(!data){
return
}
full
&& this.clear()
this.dom = preact.render(
h(IGRibbonSet, {
data: data,
images: this.images || {},
scale: this.scale() || 1,
}),
this.viewer[0],
this.dom)
return this
},
clear: function(){
if(this.dom){
this.dom.remove()
delete this.dom
}
return this
},
} }
RibbonsPrototype.__proto__ = ribbons.BaseRibbons.prototype RibbonsPrototype.__proto__ = ribbons.BaseRibbons.prototype
@ -116,6 +201,22 @@ object.makeConstructor('Ribbons',
/*********************************************************************/ /*********************************************************************/
// Checklist:
// - full ribbons:
// - build the initial DOM - DONE
// - centering - DONE
// - scaling - DONE (save/restore does not work)
// - ribbon up/down navigation - XXX
// XXX BUG: up does not hit limit on top ribbon,
// similar thing sometimes happened on down...
// XXX see if we need to put .focusRibbon(..) in ui???
// - shifting images - XXX
// - preview setting -
// - marks -
// - partial ribbons:
// - XXX
//
//
var RenderActions = actions.Actions({ var RenderActions = actions.Actions({
get dom(){ get dom(){
@ -143,18 +244,47 @@ var RenderActions = actions.Actions({
this.reload() this.reload()
} }
}], }],
// XXX do a full reload...
reload: [ reload: [
function(){ function(force){
// full reload...
if(force == 'full'){
//this.stop()
/*
killAllWorkers()
.done(function(){
reload()
})
*/
return location.reload()
}
// XXX is this correct here???
this.ribbons.preventTransitions()
if(!this.ribbons){
return
}
// XXX need to get the data...
// XXX // XXX
this.ribbons.update(this.data, force)
this.ribbons.restoreTransitions()
}], }],
// XXX refresh the previews...
refresh: [ refresh: [
function(){ function(){
if(!this.ribbons){
return
}
// XXX need to get the data...
// XXX // XXX
this.ribbons.update(this.data)
}], }],
clear: [ clear: [
function(){ function(){ this.ribbons && this.ribbons.clear() }],
// XXX
}],
resizing: [ resizing: [
core.notUserCallable(function(unit, size, overflow){ core.notUserCallable(function(unit, size, overflow){
@ -174,32 +304,56 @@ var RenderActions = actions.Actions({
viewScale: ['- Zoom/', viewScale: ['- Zoom/',
function(scale){ function(scale){
if(!this.ribbons){
return
}
if(scale == null || scale == '?'){ if(scale == null || scale == '?'){
return // XXX get scale... return this.ribbons.scale()
} }
this.resizing.chainCall(this, function(){ this.resizing.chainCall(this, function(){
// XXX set scale... this.ribbons.scale(scale)
}, 'scale', scale) }, 'scale', scale)
}], }],
fitImage: ['Zoom/Fit image', fitImage: ['Zoom/Fit image',
function(count, overflow){ function(count, overflow){
if(!this.ribbons){
return
}
if(count == '?'){ if(count == '?'){
return // XXX get size... return this.ribbons.getScreenWidthImages()
} }
this.resizing.chainCall(this, function(){ this.resizing.chainCall(this, function(){
// XXX if(count != null){
overflow = overflow == false ? 0 : overflow
var o = overflow != null ? overflow
: count % 2 != 1 ? 0
: (this.config['fit-overflow'] || 0)
count += o
}
// set the scale...
this.ribbons.fitImage(count)
// XXX refresh image previews...
}, 'screenwidth', count, overflow) }, 'screenwidth', count, overflow)
}], }],
fitRibbon: ['Zoom/Fit ribbon vertically', fitRibbon: ['Zoom/Fit ribbon vertically',
function(count, whole){ function(count, whole){
if(!this.ribbons){
return
}
if(count == '?'){ if(count == '?'){
return // XXX get size... return this.ribbons.getScreenHeightRibbons()
} }
this.resizing.chainCall(this, function(){ this.resizing.chainCall(this, function(){
// XXX set size... this.ribbons.fitRibbon(count, whole)
// XXX refresh image previews...
}, 'screenheight', count, whole) }, 'screenheight', count, whole)
}], }],
@ -207,17 +361,45 @@ var RenderActions = actions.Actions({
centerImage: ['- Interface/Center an image in ribbon horizontally', centerImage: ['- Interface/Center an image in ribbon horizontally',
function(target, align, offset, scale){ function(target, align, offset, scale){
// XXX this.ribbons && this.ribbons.centerImage(target, align, offset, scale) }],
}],
centerRibbon: ['- Interface/Center a ribbon vertically', centerRibbon: ['- Interface/Center a ribbon vertically',
function(target){ function(target){
// XXX this.ribbons && this.ribbons.centerRibbon(target) }],
}],
ribbonRotation: ['- Interface|Ribbon/', ribbonRotation: ['- Interface|Ribbon/',
function(angle){ function(angle){
// XXX // XXX
}], }],
// XXX should these be here, in ui or in ribbons???
// XXX these are identical to features/ui-ribbons.js
focusRibbon: [
function(target, mode){
mode = mode || this.config['ribbon-focus-mode']
var c = this.data.getRibbonOrder()
var i = this.data.getRibbonOrder(target)
// NOTE: we are not changing the direction here based on
// this.direction as swap will confuse the user...
var direction = c < i ? 'before' : 'after'
if(mode == 'visual'){
var ribbons = this.ribbons
var r = this.data.getRibbon(target)
var t = ribbons.getImageByPosition('current', r)
if(t.length > 1){
t = t.eq(direction == 'before' ? 0 : 1)
}
t = ribbons.elemGID(t)
this.focusImage(t, r)
}
}],
}) })
var Render = var Render =
@ -234,7 +416,16 @@ module.Render = core.ImageGridFeatures.Feature({
actions: RenderActions, actions: RenderActions,
handlers: [ handlers: [
// XXX [[
'shiftImageTo',
'shiftImageUp',
'shiftImageDown',
'shiftImageLeft',
'shiftImageRight',
], function(){
// XXX stub...
this.reload()
}],
], ],
}) })

View File

@ -153,7 +153,7 @@ actions.Actions({
reload() reload()
}) })
*/ */
location.reload() return location.reload()
} }
this.ribbons.preventTransitions() this.ribbons.preventTransitions()
@ -295,6 +295,8 @@ actions.Actions({
}], }],
// XXX should these be here, in ui or in ribbons???
// XXX these are identical to features/ui-preact-render.js
focusImage: [ focusImage: [
function(target, list){ function(target, list){
return function(){ return function(){

View File

@ -1314,6 +1314,7 @@ var ControlActions = actions.Actions({
// XXX do not do anything on viewer focus... (???) // XXX do not do anything on viewer focus... (???)
// XXX depends on .ribbons... // XXX depends on .ribbons...
// XXX uses: .focusImage(..)
toggleImageClickHandling: ['Interface/Image click handling', toggleImageClickHandling: ['Interface/Image click handling',
toggler.Toggler(null, toggler.Toggler(null,
function(_, new_state){ function(_, new_state){
@ -1518,6 +1519,7 @@ var ControlActions = actions.Actions({
// ...found the problem, need to disable transitions for this // ...found the problem, need to disable transitions for this
// to work semi smoothly... // to work semi smoothly...
// XXX depends on .ribbons... // XXX depends on .ribbons...
// XXX uses: .focusImage(..)
toggleRibbonPanHandling: ['Interface/Ribbon pan handling', toggleRibbonPanHandling: ['Interface/Ribbon pan handling',
toggler.Toggler(null, toggler.Toggler(null,
function(_, new_state){ function(_, new_state){
@ -1756,6 +1758,7 @@ var ControlActions = actions.Actions({
// XXX BUG?: acceleration seems to be increasing with time... // XXX BUG?: acceleration seems to be increasing with time...
// XXX add a "ribbonWheeling" ( ;) ) event a-la ribbonPanning... // XXX add a "ribbonWheeling" ( ;) ) event a-la ribbonPanning...
// XXX depends on .ribbons... // XXX depends on .ribbons...
// XXX uses: .focusImage(..)
toggleMouseWheelHandling: ['Interface/Mouse wheel handling', toggleMouseWheelHandling: ['Interface/Mouse wheel handling',
toggler.Toggler(null, toggler.Toggler(null,
function(_, new_state){ function(_, new_state){

View File

@ -350,7 +350,6 @@ var BaseRibbonsPrototype = {
return this return this
}, },
// Get visible image tile size... // Get visible image tile size...
// //
// .getVisibleImageSize() // .getVisibleImageSize()
@ -369,6 +368,7 @@ var BaseRibbonsPrototype = {
// //
// XXX this might break when no images are loaded and proportions // XXX this might break when no images are loaded and proportions
// are not square... // are not square...
// XXX this depends on .createImage(..)
getVisibleImageSize: function(dim, scale, img, force){ getVisibleImageSize: function(dim, scale, img, force){
dim = dim == null ? 'width' : dim dim = dim == null ? 'width' : dim
img = img || this.viewer.find(IMAGE) img = img || this.viewer.find(IMAGE)
@ -385,7 +385,7 @@ var BaseRibbonsPrototype = {
// if no images are loaded create one temporarily.... // if no images are loaded create one temporarily....
if(img.length == 0){ if(img.length == 0){
img = tmp = this.createImage('__tmp_image__') img = tmp = $(this.createImage('__tmp_image__'))
.css({ .css({
position: 'absolute', position: 'absolute',
visibility: 'hidden', visibility: 'hidden',
@ -449,6 +449,68 @@ var BaseRibbonsPrototype = {
return H/h return H/h
}, },
// Fit image to view...
//
// If n is given this will fit n images (default: 1)
//
// NOTE: this will never scale the view in a way that an image
// overflows either in height nor width.
//
// XXX might be useful to set origin before scaling...
fitImage: function(n, min){
n = n || 1
// NOTE: this is width oriented...
var scale = this.getScreenWidthImages(1, min) / n
// check bounds...
var H = this.viewer.height()
var h = this.getVisibleImageSize('height', 1)
// n images will be higher than the viewer, adjust for height...
if(h*scale >= H){
scale = H/h
}
this
.scale(scale)
//.centerRibbon(null, null, scale)
//.centerImage(null, null, null, scale)
return this
},
// NOTE: if fit_whole_images is true (default) this will fit a discrete
// number of images in width...
// XXX this does not account for ribbon spacing...
fitRibbon: function(n, fit_whole_images){
n = n || 1
fit_whole_images = fit_whole_images == null ? true : false
var scale = this.getScreenHeightRibbons(1) / n
var w = this.getVisibleImageSize('width', 1)
var W = this.viewer.width()
// n ribbons will be wider than the viewer...
if(w*scale >= W){
scale = W/w
}
// shift the scale to the point where screen width is a whole
// number of images...
if(fit_whole_images){
var d = this.getScreenWidthImages(scale)
d = d / Math.ceil(d)
scale *= d
}
this.scale(scale)
return this
},
// Contextual getters... // Contextual getters...
// Get ribbon-set... // Get ribbon-set...
@ -2489,66 +2551,6 @@ var RibbonsPrototype = {
return this.flipImage(target, 'horizontal', reference) }, return this.flipImage(target, 'horizontal', reference) },
// Fit image to view...
//
// If n is given this will fit n images (default: 1)
//
// NOTE: this will never scale the view in a way that an image
// overflows either in height nor width.
//
// XXX might be useful to set origin before scaling...
fitImage: function(n, min){
n = n || 1
// NOTE: this is width oriented...
var scale = this.getScreenWidthImages(1, min) / n
// check bounds...
var H = this.viewer.height()
var h = this.getVisibleImageSize('height', 1)
// n images will be higher than the viewer, adjust for height...
if(h*scale >= H){
scale = H/h
}
this
.scale(scale)
//.centerRibbon(null, null, scale)
//.centerImage(null, null, null, scale)
return this
},
// NOTE: if fit_whole_images is true (default) this will fit a discrete
// number of images in width...
// XXX this does not account for ribbon spacing...
fitRibbon: function(n, fit_whole_images){
n = n || 1
fit_whole_images = fit_whole_images == null ? true : false
var scale = this.getScreenHeightRibbons(1) / n
var w = this.getVisibleImageSize('width', 1)
var W = this.viewer.width()
// n ribbons will be wider than the viewer...
if(w*scale >= W){
scale = W/w
}
// shift the scale to the point where screen width is a whole
// number of images...
if(fit_whole_images){
var d = this.getScreenWidthImages(scale)
d = d / Math.ceil(d)
scale *= d
}
this.scale(scale)
return this
},
} }
RibbonsPrototype.__proto__ = BaseRibbonsPrototype RibbonsPrototype.__proto__ = BaseRibbonsPrototype