PDA

View Full Version : Pinch Image with carousel and working fine



Perdiga
23 Apr 2012, 12:38 PM
index.html


<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>ImageViewer Example</title>

<link rel="stylesheet" type="text/css" href="http://docs.sencha.com/touch/2-0/touch/resources/css/sencha-touch.css">
<script type="text/javascript" src="http://docs.sencha.com/touch/2-0/touch/sencha-touch-all-debug.js"></script>


<script type="text/javascript" src="ImageViewer.js"></script>

<script type="text/javascript">
Ext.application({

name: 'ImageExample'

,launch: function() {

Ext.define('WPMobile.Viewport', {
extend: 'Ext.Carousel',
xtype: 'my-viewport',
config: {
fullscreen: true,
layout: 'fit',
items: [
{
xtype: 'imageviewer',
style: {
backgroundColor: '#255'
},
imageSrc: 'http://cdn.macrumors.com/article/2010/09/03/145454-itunes_10_icon.jpg'
},
{
xtype: 'imageviewer',
style: {
backgroundColor: '#255'
},
imageSrc: 'http://www.baixandowallpapers.com/wallpapers/03-2011/lua-cheia-paisagem-noite-1299711122.jpg'
},
{
xtype: 'imageviewer',
style: {
backgroundColor: '#255'
},
imageSrc: 'http://www.baixandowallpapers.com/wallpapers/03-2011/lua-cheia-paisagem-noite-1299711122.jpg'
}
],
listeners: {
activeitemchange: function( container,value, oldValue,eOpts ){
oldValue.resetZoom();
this.getActiveItem().rotate();
},
resize: function( component , eOpts ){
this.getActiveItem().rotate();
}

},
},

onDragStart: function (e) {
var scroller = this.getActiveItem().getScrollable().getScroller();
if (e.targetTouches.length == 1 && (e.deltaX < 0 && scroller.getMaxPosition().x === scroller.position.x) || (e.deltaX > 0 && scroller.position.x == 0)) {
this.callParent(arguments);
}
},
onDrag: function (e) {
if (e.targetTouches.length == 1)
this.callParent(arguments);
},
onDragEnd: function (e) {
if (e.targetTouches.length < 2)
this.callParent(arguments);
}


});




Ext.create('WPMobile.Viewport', {
id: 'viewport'
});

}
});
</script>


</head>


<body></body>
</html>


ImageViewer.js



Ext.define('Arkivus.ImageViewer',{

extend: 'Ext.Container',
config: {
doubleTapScale: 1
,maxScale: 4
,loadingMask: true
,previewSrc: false
,resizeOnLoad:true
,imageSrc: false
,initOnActivate: false
,cls: 'imageBox'
,scrollable: 'both'
,html: '<figure><img></figure>'
}
,xtype: 'imageviewer'
,initialize: function() {
if(this.initOnActivate)
this.addListener('activate', this.initViewer, this, {delay: 10, single: true});
else
this.addListener('painted', this.initViewer, this, {delay: 10, single: true});
}

,initViewer: function() {

//disable scroller
var scroller = this.getScrollable().getScroller();
scroller.setDisabled(true);

// mask image viewer
if(this.getLoadingMask())
this.setMasked({
xtype: 'loadmask',
});


// retrieve DOM els
this.figEl = this.element.down('figure');
this.imgEl = this.figEl.down('img');


// apply required styles
this.figEl.setStyle({
overflow: 'hidden'
,display: 'block'
,margin: 0
});


this.imgEl.setStyle({
'-webkit-user-drag': 'none'
,'-webkit-transform-origin': '0 0'
,'visibility': 'hidden'
});


// show preview
if(this.getPreviewSrc())
{
this.element.setStyle({
backgroundImage: 'url('+this.getPreviewSrc()+')'
,backgroundPosition: 'center center'
,backgroundRepeat: 'no-repeat'
,webkitBackgroundSize: 'contain'
});
}


// attach event listeners
this.on('load', this.onImageLoad, this);
this.imgEl.addListener({
scope: this
,doubletap: this.onDoubleTap
,pinchstart: this.onImagePinchStart
,pinch: this.onImagePinch
,pinchend: this.onImagePinchEnd
});


// load image
if(this.getImageSrc())
this.loadImage(this.getImageSrc());
}

,loadImage: function(src) {
if(this.imgEl){
this.imgEl.dom.src = src;
this.imgEl.dom.onload = Ext.Function.bind(this.onLoad, this, this.imgEl, 0);
}
else
this.getImageSrc() = src;
}


,onLoad : function(el, e) {
this.fireEvent('load', this, el, e);
}

,onImageLoad: function() {
// get viewport size
this.viewportWidth = this.viewportWidth || this.getWidth() || this.parent.element.getWidth();
this.viewportHeight = this.viewportHeight || this.getHeight() || this.parent.element.getHeight();

// grab image size
this.imgWidth = this.imgEl.dom.width
this.imgHeight = this.imgEl.dom.height;

// calculate and apply initial scale to fit image to screen
if(this.getResizeOnLoad()){
this.scale = this.baseScale = Math.min(this.viewportWidth/this.imgWidth, this.viewportHeight/this.imgHeight);
this.setMaxScale(this.scale*4);
}else{
this.scale = this.baseScale = 1;
}

// set initial translation to center
this.translateX = this.translateBaseX = (this.viewportWidth - this.baseScale * this.imgWidth) / 2;
this.translateY = this.translateBaseY = (this.viewportHeight - this.baseScale * this.imgHeight) / 2;

// apply initial scale and translation
this.applyTransform();

// initialize scroller configuration
this.adjustScroller();


// show image and remove mask
this.imgEl.setStyle({ visibility: 'visible' });


// remove preview
if(this.getPreviewSrc())
{
this.element.setStyle({
backgroundImage: 'none'
});
}


if(this.getLoadingMask())
this.setMasked(false);


this.fireEvent('imageLoaded', this);
}

,onImagePinchStart: function(ev) {
var scroller = this.getScrollable().getScroller();


// disable scrolling during pinch
scroller.stopAnimation();
scroller.setDisabled(true);

// store beginning scale
this.startScale = this.scale;

// calculate touch midpoint relative to image viewport
this.originViewportX = (ev.touches[0].pageX + ev.touches[1].pageX) / 2 - this.element.getX();
this.originViewportY = (ev.touches[0].pageY + ev.touches[1].pageY) / 2 - this.element.getY();

// translate viewport origin to position on scaled image
this.originScaledImgX = this.originViewportX + scroller.position.x - this.translateX;
this.originScaledImgY = this.originViewportY + scroller.position.y - this.translateY;

// unscale to find origin on full size image
this.originFullImgX = this.originScaledImgX / this.scale;
this.originFullImgY = this.originScaledImgY / this.scale;

// calculate translation needed to counteract new origin and keep image in same position on screen
this.translateX += (-1 * ((this.imgWidth*(1-this.scale)) * (this.originFullImgX/this.imgWidth)));
this.translateY += (-1 * ((this.imgHeight*(1-this.scale)) * (this.originFullImgY/this.imgHeight)))

// apply new origin
this.setOrigin(this.originFullImgX, this.originFullImgY);

// apply translate and scale CSS
this.applyTransform();
}

,onImagePinch: function(ev) {
// prevent scaling to smaller than screen size
this.scale = Ext.Number.constrain(ev.scale * this.startScale, this.baseScale-2, this.getMaxScale());
this.applyTransform();
}

,onImagePinchEnd: function(ev) {

// set new translation
if(this.scale == this.baseScale)
{
// move to center
this.setTranslation(this.translateBaseX, this.translateBaseY);
}
else
{
//Resize to init size like ios
if(this.scale < this.baseScale && this.getResizeOnLoad()){
this.resetZoom();
return;
}
// calculate rescaled origin
this.originReScaledImgX = this.originScaledImgX * (this.scale / this.startScale);
this.originReScaledImgY = this.originScaledImgY * (this.scale / this.startScale);

// maintain zoom position
this.setTranslation(this.originViewportX - this.originReScaledImgX, this.originViewportY - this.originReScaledImgY);
}
// reset origin and update transform with new translation
this.setOrigin(0, 0);
this.applyTransform();


// adjust scroll container
this.adjustScroller();
}



,onDoubleTap: function(ev, t) {
var that = this;
var scroller = this.getScrollable().getScroller();
if(!this.getDoubleTapScale())
return false;

// set scale and translation
if(this.scale > this.baseScale)
{
// zoom out to base view
this.scale = this.baseScale;
this.setTranslation(this.translateBaseX, this.translateBaseY);
// reset origin and update transform with new translation
this.applyTransform();


// adjust scroll container
this.adjustScroller();

// force repaint to solve occasional iOS rendering delay
Ext.repaint();
}
else
{
// zoom in toward tap position
var oldScale = this.scale
,newScale = this.baseScale*4
,originViewportX = ev ? (ev.pageX - this.element.getX()) : 0
,originViewportY = ev ? (ev.pageY - this.element.getY()) : 0
,originScaledImgX = originViewportX + scroller.position.x - this.translateX
,originScaledImgY = originViewportY + scroller.position.y - this.translateY
,originReScaledImgX = originScaledImgX * (newScale / oldScale)
,originReScaledImgY = originScaledImgY * (newScale / oldScale);

this.scale = newScale;

//smoothes the transition
setTimeout(function(){
that.setTranslation(originViewportX - originReScaledImgX, originViewportY - originReScaledImgY);
// reset origin and update transform with new translation
that.applyTransform();


// adjust scroll container
that.adjustScroller();

// force repaint to solve occasional iOS rendering delay
Ext.repaint();
},50)

}


}

,setOrigin: function(x, y) {
this.imgEl.dom.style.webkitTransformOrigin = x+'px '+y+'px';
}

,setTranslation: function(translateX, translateY) {
this.translateX = translateX;
this.translateY = translateY;

// transfer negative translations to scroll offset
this.scrollX = this.scrollY = 0;

if(this.translateX < 0)
{
this.scrollX = this.translateX;
this.translateX = 0;
}
if(this.translateY < 0)
{
this.scrollY = this.translateY;
this.translateY = 0;
}
}

,resetZoom:function(){
//Resize to init size like ios
this.scale = this.baseScale;

this.setTranslation(this.translateBaseX, this.translateBaseY);

// reset origin and update transform with new translation
this.setOrigin(0, 0);
this.applyTransform();


// adjust scroll container
this.adjustScroller();

}
,rotate:function(){
// get viewport size
this.viewportWidth = this.parent.element.getWidth() ||this.viewportWidth || this.getWidth();
this.viewportHeight = this.parent.element.getHeight() || this.viewportHeight || this.getHeight();


// grab image size
this.imgWidth = this.imgEl.dom.width
this.imgHeight = this.imgEl.dom.height;

// calculate and apply initial scale to fit image to screen
if(this.getResizeOnLoad()){
this.scale = this.baseScale = Math.min(this.viewportWidth/this.imgWidth, this.viewportHeight/this.imgHeight);
this.setMaxScale(this.scale*4);
}else{
this.scale = this.baseScale = 1;
}

// set initial translation to center
this.translateX = this.translateBaseX = (this.viewportWidth - this.baseScale * this.imgWidth) / 2;
this.translateY = this.translateBaseY = (this.viewportHeight - this.baseScale * this.imgHeight) / 2;

// apply initial scale and translation
this.applyTransform();

// initialize scroller configuration
this.adjustScroller();

}


,applyTransform: function() {
var fixedX = Ext.Number.toFixed(this.translateX,5)
,fixedY = Ext.Number.toFixed(this.translateY,5)
,fixedScale = Ext.Number.toFixed(this.scale, 8);

if(Ext.os.is.Android)
{
this.imgEl.dom.style.webkitTransform =
//'translate('+fixedX+'px, '+fixedY+'px)'
//+' scale('+fixedScale+','+fixedScale+')';
'matrix('+fixedScale+',0,0,'+fixedScale+','+fixedX+','+fixedY+')'
}
else
{
this.imgEl.dom.style.webkitTransform =
'translate3d('+fixedX+'px, '+fixedY+'px, 0)'
+' scale3d('+fixedScale+','+fixedScale+',1)';
}
}




,adjustScroller: function() {
var scroller = this.getScrollable().getScroller();

// disable scrolling if zoomed out completely, else enable it
if(this.scale == this.baseScale)
scroller.setDisabled(true);
else
scroller.setDisabled(false);

// size container to final image size
var boundWidth = Math.max(this.imgWidth * this.scale, this.viewportWidth);
var boundHeight = Math.max(this.imgHeight * this.scale, this.viewportHeight);


this.figEl.setStyle({
width: boundWidth + 'px'
,height: boundHeight + 'px'
});

// update scroller to new content size
scroller.refresh();


// apply scroll
var x = 0;
if(this.scrollX){
x = this.scrollX
}
var y = 0;
if(this.scrollY){
y = this.scrollY
}
scroller.scrollTo(x*-1,y*-1)
}
});




thanks to Armode for the help

I was tested in iOS 5.0, 5.1 with ipad 1,2,3 and with galaxy tab 8.9 with android 3.2
works fine.

Gaelmart
24 Apr 2012, 12:50 AM
Well done lads.
Double click on android 2.3 works great, best we can hope for.
Did someone mention adding 'zoomIn/zoomOut Buttons for Android' as 2.3 is 95% of market.

Gary

sebayo
24 Apr 2012, 5:22 AM
Hi
Perdiga great job!
i have some problems when i compile an apk using phonegap. iīm testing in a motorola zoom tablet with the last android, the problems are:
flicking when i pinch the image, sometimes disapear and appears again zoomed,
sometimes i canīt swipe when the image itīs zoomed.
thanks for this great example

armode
24 Apr 2012, 5:30 AM
flicking when i pinch the image, sometimes disapear and appears again zoomed,
sometimes i canīt swipe when the image itīs zoomed.


I had simular problems and think, that the problem is to listen to the "resize" event. If I recognize the "flicking-issue", the resize event is fired permantly. Maybe we have to listen to the orientationchange event from Viewport?

SunboX
24 Apr 2012, 5:32 AM
hereīs a nice SlideShare from one of Flickrīs mobile developers on native zoomin into images:

Quote: "Why you can’t use native Pinch to Zoom"
http://www.slideshare.net/ysaw/creating-responsive-html5-touch-interfaces/31

greetings Sunny

SunboX
24 Apr 2012, 5:35 AM
and the corresponding video presentation:
http://www.youtube.com/watch?v=lcD9CF0bxyk

greetings Sunny

armode
24 Apr 2012, 7:11 AM
Maybe we have to listen to the orientationchange event from Viewport?


Adding a listener to the Viewport for example in line 70 seems to solve that flicking-issue:



Ext.Viewport.on('orientationchange', this.rotate, this, {buffer: 50 });


The resize event is maybe not the best choice, see ST API:
"Important note: For the best performance on mobile devices, use this only when you absolutely need to monitor a Component's size.
Note: This event is not available to be used with event delegation. Instead 'resize' only fires if you explicily add at least one listener to it, due to performance reason."

sebayo
24 Apr 2012, 8:41 AM
Adding a listener to the Viewport for example in line 70 seems to solve that flicking-issue:

Works better but when you pinch in the first place the image flickering and try to change itīs scale, you can see the rectangle changing positions, then works for moments but the zooming isn't fluid.

Perdiga
24 Apr 2012, 9:51 AM
Adding a listener to the Viewport for example in line 70 seems to solve that flicking-issue:



Ext.Viewport.on('orientationchange', this.rotate, this, {buffer: 50 });


The resize event is maybe not the best choice, see ST API:
"Important note: For the best performance on mobile devices, use this only when you absolutely need to monitor a Component's size.
Note: This event is not available to be used with event delegation. Instead 'resize' only fires if you explicily add at least one listener to it, due to performance reason."

thanks ,I already added this in code


Well done lads.
Double click on android 2.3 works great, best we can hope for.
Did someone mention adding 'zoomIn/zoomOut Buttons for Android' as 2.3 is 95% of market.

Gary

you can use doubletap,

sephyroth69
24 Apr 2012, 12:37 PM
Guys I must say this is down right awesome. Exactly what I was looking for.

A few corrections to improve potential bugs :
there is a coma that shouldn't be her:

if(this.getLoadingMask())
this.setMasked({
xtype: 'loadmask',
});
Missing semicolon :


// grab image size
this.imgWidth = this.imgEl.dom.width

Missing semicolon :


this.translateY += (-1 * ((this.imgHeight * (1 - this.scale)) * (this.originFullImgY / this.imgHeight)))

Missing semicolon in rotate function :


this.imgWidth = this.imgEl.dom.width

hotdp
24 Apr 2012, 11:49 PM
@Perdig (http://www.sencha.com/forum/member.php?352191-Perdiga) Great job on this! Just what I need.

It really works great on iPhone, but not so well on Android:

Its very laggy on Android 4.0.3, any solutions to this?

I have anther HTC Android phone but when I zoom, the whole application zooms. Do someone know how I could prevent this?

sephyroth69
24 Apr 2012, 11:54 PM
@hotdp Android issue is a known one and there is a bug report about it if you want to contribute (http://code.google.com/p/android/issues/detail?id=25147). It's Android's browser fault which is crappy with CSS3 animations.

hotdp
24 Apr 2012, 11:57 PM
@hotdp Android issue is a known one and there is a bug report about it if you want to contribute (http://code.google.com/p/android/issues/detail?id=25147). It's Android's browser fault which is crappy with CSS3 animations.

Did contribute from day one.
But asked to get it confirmed if that was the problem. Did not know for sure, just saw 'matrix' in the code if Android so did not know if the performance problem was something else.

sephyroth69
24 Apr 2012, 11:59 PM
I don't know for sure either, I'm just guessing that it's related.

demon222
25 Apr 2012, 1:02 AM
corect code!


listeners: {
activeitemchange: function( container,value, oldValue,eOpts ){
if(typeof(oldValue) != 'undefined') { // must check if undefined!!!!!!!!!!!!!!!!
oldValue.resetZoom();
this.getActiveItem().rotate();
}
},
resize: function( component , eOpts ){
this.getActiveItem().rotate();
}
}



and CSS helpfull link : http://www.westciv.com/tools/3Dtransforms/index.html

armode
25 Apr 2012, 5:39 AM
you can use doubletap,

For my use case just double taping is not enough, that's why I added zoomIn/Out Buttons to my global Toolbar.
I didn't know how to connect to the ImageViewer component, that's why I fire zoomIn and zoomOut-events on viewport and listen to that event inside the imageViewer component. Maybe someone has a better idea? Anyway, it works fine:

Adding two more listeners:


Ext.Viewport.on('zoomIn', this.onZoomIn, this);
Ext.Viewport.on('zoomOut', this.onZoomOut, this);


And three functions for zooming step by step;


,onZoomIn: function(){
var myScale = this.scale;
if (myScale < this.getMaxScale())
myScale = this.scale + 0.05;
if (myScale >= this.getMaxScale())
myScale = this.getMaxScale();
var ev = {pageX : 0, pageY: 0};
ev.pageX = this.viewportWidth / 2;
ev.pageY = this.viewportHeight / 2;
this.zoomImage(ev,myScale);
}

,onZoomOut: function(){
var myScale = this.scale;
if (myScale > this.baseScale)
myScale = this.scale - 0.05;
if (myScale <= this.baseScale)
myScale = this.baseScale;

var ev = {pageX : 0, pageY: 0};
ev.pageX = this.viewportWidth / 2;
ev.pageY = this.viewportHeight / 2;
this.zoomImage(ev,myScale);
}

,zoomImage: function (ev, scale, scope) {
var scroller = this.getScrollable().getScroller();
var that = this;
// zoom in toward tap position
var oldScale = this.scale
,newScale = scale
,originViewportX = ev ? (ev.pageX - this.element.getX()) : 0
,originViewportY = ev ? (ev.pageY - this.element.getY()) : 0
,originScaledImgX = originViewportX + scroller.position.x - this.translateX
,originScaledImgY = originViewportY + scroller.position.y - this.translateY
,originReScaledImgX = originScaledImgX * (newScale / oldScale)
,originReScaledImgY = originScaledImgY * (newScale / oldScale)

this.scale = newScale;
setTimeout(function(){
that.setTranslation(originViewportX - originReScaledImgX, originViewportY - originReScaledImgY);

// reset origin and update transform with new translation
that.applyTransform();

// adjust scroll container
that.adjustScroller();

// force repaint to solve occasional iOS rendering delay
Ext.repaint();
},50)
}



I had to adjust the value for ev.pageY and add the height of my toolbar!

armode
25 Apr 2012, 5:57 AM
There's a bug, if you zoom out using the pinch gesture. How to reproduce:

double tap to zoom in 100%
swipe/scroll to the upper right corner
pinch once a little bit to zoom out
scroll to the left and pinch a second time to zoom out

The effect is that the image get cuts off on the right side and on the left, there's a border!
See screenshot:
34503

Perdiga
25 Apr 2012, 10:14 AM
There's a bug, if you zoom out using the pinch gesture. How to reproduce:

double tap to zoom in 100%
swipe/scroll to the upper right corner
pinch once a little bit to zoom out
scroll to the left and pinch a second time to zoom out
The effect is that the image get cuts off on the right side and on the left, there's a border!
See screenshot:
34503


I had seen this bug, but i don't know how fix it .. i am trying something here



For my use case just double taping is not enough, that's why I added zoomIn/Out Buttons to my global Toolbar.
I didn't know how to connect to the ImageViewer component, that's why I fire zoomIn and zoomOut-events on viewport and listen to that event inside the imageViewer component. Maybe someone has a better idea? Anyway, it works fine:

Adding two more listeners:


Ext.Viewport.on('zoomIn', this.onZoomIn, this);
Ext.Viewport.on('zoomOut', this.onZoomOut, this);


And three functions for zooming step by step;


,onZoomIn: function(){
var myScale = this.scale;
if (myScale < this.getMaxScale())
myScale = this.scale + 0.05;
if (myScale >= this.getMaxScale())
myScale = this.getMaxScale();
var ev = {pageX : 0, pageY: 0};
ev.pageX = this.viewportWidth / 2;
ev.pageY = this.viewportHeight / 2;
this.zoomImage(ev,myScale);
}

,onZoomOut: function(){
var myScale = this.scale;
if (myScale > this.baseScale)
myScale = this.scale - 0.05;
if (myScale <= this.baseScale)
myScale = this.baseScale;

var ev = {pageX : 0, pageY: 0};
ev.pageX = this.viewportWidth / 2;
ev.pageY = this.viewportHeight / 2;
this.zoomImage(ev,myScale);
}

,zoomImage: function (ev, scale, scope) {
var scroller = this.getScrollable().getScroller();
var that = this;
// zoom in toward tap position
var oldScale = this.scale
,newScale = scale
,originViewportX = ev ? (ev.pageX - this.element.getX()) : 0
,originViewportY = ev ? (ev.pageY - this.element.getY()) : 0
,originScaledImgX = originViewportX + scroller.position.x - this.translateX
,originScaledImgY = originViewportY + scroller.position.y - this.translateY
,originReScaledImgX = originScaledImgX * (newScale / oldScale)
,originReScaledImgY = originScaledImgY * (newScale / oldScale)

this.scale = newScale;
setTimeout(function(){
that.setTranslation(originViewportX - originReScaledImgX, originViewportY - originReScaledImgY);

// reset origin and update transform with new translation
that.applyTransform();

// adjust scroll container
that.adjustScroller();

// force repaint to solve occasional iOS rendering delay
Ext.repaint();
},50)
}



I had to adjust the value for ev.pageY and add the height of my toolbar!

you can get the imageViewer and call the method
I'll update in a moment the component with this

Perdiga
25 Apr 2012, 10:19 AM
The new code with ZoomIn/ZoomOut... there is a bug in that i am working to fix

Index.html


<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>ImageViewer Example</title>

<link rel="stylesheet" type="text/css" href="http://docs.sencha.com/touch/2-0/touch/resources/css/sencha-touch.css">
<script type="text/javascript" src="sencha-touch-all-debug.js"></script>


<script type="text/javascript" src="ImageViewer.js"></script>

<script type="text/javascript">
Ext.application({

name: 'ImageExample'

,launch: function() {

Ext.define('WPMobile.Viewport', {
extend: 'Ext.Carousel',
xtype: 'my-viewport',
config: {
//fullscreen: true,
//layout: 'fit',
items: [
{
xtype: 'imageviewer',
style: {
backgroundColor: '#255'
},
imageSrc: 'http://cdn.macrumors.com/article/2010/09/03/145454-itunes_10_icon.jpg'
},
{
xtype: 'imageviewer',
style: {
backgroundColor: '#255'
},
imageSrc: 'http://www.baixandowallpapers.com/wallpapers/03-2011/lua-cheia-paisagem-noite-1299711122.jpg'
},
{
xtype: 'imageviewer',
style: {
backgroundColor: '#255'
},
imageSrc: 'http://www.baixandowallpapers.com/wallpapers/03-2011/lua-cheia-paisagem-noite-1299711122.jpg'
}
],
listeners: {
activeitemchange: function( container,value, oldValue,eOpts ){
if(oldValue){
//oldValue.resetZoom();
this.getActiveItem().resize();
}
},
resize: function( component , eOpts ){
this.getActiveItem().resize();
}
},
},
onDragStart: function (e) {
var scroller = this.getActiveItem().getScrollable().getScroller();
if (e.targetTouches.length == 1 && (e.deltaX < 0 && scroller.getMaxPosition().x === scroller.position.x) || (e.deltaX > 0 && scroller.position.x == 0)) {
this.callParent(arguments);
}
},
onDrag: function (e) {
if (e.targetTouches.length == 1)
this.callParent(arguments);
},
onDragEnd: function (e) {
if (e.targetTouches.length < 2)
this.callParent(arguments);
}

});

Ext.define('WPMobile.ViewportPanel', {
extend: 'Ext.Panel',
xtype: 'my-viewport-panel',


config: {
fullscreen: true,
layout: 'fit',
items: [

{
xtype: 'titlebar',
docked: 'top',


items: [
{ text: 'ZoomIn',
listeners: {
tap:function(){
Ext.getCmp('myCarousel').getActiveItem().onZoomIn();
}
},
},
{ text: 'ZoomOut' ,
listeners: {
tap:function(){
Ext.getCmp('myCarousel').getActiveItem().onZoomOut();
},
},

},
]
},
{
xtype:'my-viewport',
id:'myCarousel'
},
{
xtype: 'titlebar',
docked: 'bottom',


items: [
{ text: 'ZoomIn',
listeners: {
tap:function(){
Ext.getCmp('myCarousel').getActiveItem().onZoomIn();
}
},
},
{ text: 'ZoomOut' ,
listeners: {
tap:function(){
Ext.getCmp('myCarousel').getActiveItem().onZoomOut();
},
},

},
]
},
],
},

});


Ext.Viewport.add({xtype:'my-viewport-panel'});


}
});
</script>


</head>


<body></body>
</html>


imageViewer.js



Ext.define('Arkivus.ImageViewer',{
extend: 'Ext.Container',
config: {
doubleTapScale: 1
,maxScale: 4
,loadingMask: true
,previewSrc: false
,resizeOnLoad:true
,imageSrc: false
,initOnActivate: false
,cls: 'imageBox'
,scrollable: 'both'
,html: '<figure><img></figure>'
}
,xtype: 'imageviewer'
,initialize: function() {
if(this.initOnActivate)
this.addListener('activate', this.initViewer, this, {delay: 10, single: true});
else
this.addListener('painted', this.initViewer, this, {delay: 10, single: true});
}

,initViewer: function() {

//disable scroller
var scroller = this.getScrollable().getScroller();
scroller.setDisabled(true);

// mask image viewer
if(this.getLoadingMask())
this.setMasked({
xtype: 'loadmask',
});




// retrieve DOM els
this.figEl = this.element.down('figure');
this.imgEl = this.figEl.down('img');




// apply required styles
this.figEl.setStyle({
overflow: 'hidden'
,display: 'block'
,margin: 0
});




this.imgEl.setStyle({
'-webkit-user-drag': 'none'
,'-webkit-transform-origin': '0 0'
,'visibility': 'hidden'
});




// show preview
if(this.getPreviewSrc())
{
this.element.setStyle({
backgroundImage: 'url('+this.getPreviewSrc()+')'
,backgroundPosition: 'center center'
,backgroundRepeat: 'no-repeat'
,webkitBackgroundSize: 'contain'
});
}




// attach event listeners
this.on('load', this.onImageLoad, this);
this.imgEl.addListener({
scope: this
,doubletap: this.onDoubleTap
,pinchstart: this.onImagePinchStart
,pinch: this.onImagePinch
,pinchend: this.onImagePinchEnd
});




// load image
if(this.getImageSrc())
this.loadImage(this.getImageSrc());
}

,loadImage: function(src) {
if(this.imgEl){
this.imgEl.dom.src = src;
this.imgEl.dom.onload = Ext.Function.bind(this.onLoad, this, this.imgEl, 0);
}
else
this.getImageSrc() = src;
}




,onLoad : function(el, e) {
this.fireEvent('load', this, el, e);
}

,onImageLoad: function() {
// get viewport size
this.viewportWidth = this.viewportWidth || this.getWidth() || this.parent.element.getWidth();
this.viewportHeight = this.viewportHeight || this.getHeight() || this.parent.element.getHeight();

// grab image size
this.imgWidth = this.imgEl.dom.width
this.imgHeight = this.imgEl.dom.height;

// calculate and apply initial scale to fit image to screen
if(this.getResizeOnLoad()){
this.scale = this.baseScale = Math.min(this.viewportWidth/this.imgWidth, this.viewportHeight/this.imgHeight);
this.setMaxScale(this.scale*4);
}else{
this.scale = this.baseScale = 1;
}

// set initial translation to center
this.translateX = this.translateBaseX = (this.viewportWidth - this.baseScale * this.imgWidth) / 2;
this.translateY = this.translateBaseY = (this.viewportHeight - this.baseScale * this.imgHeight) / 2;

// apply initial scale and translation
this.applyTransform();

// initialize scroller configuration
this.adjustScroller();




// show image and remove mask
this.imgEl.setStyle({ visibility: 'visible' });




// remove preview
if(this.getPreviewSrc())
{
this.element.setStyle({
backgroundImage: 'none'
});
}




if(this.getLoadingMask())
this.setMasked(false);




this.fireEvent('imageLoaded', this);
}

,onImagePinchStart: function(ev) {
var scroller = this.getScrollable().getScroller();




// disable scrolling during pinch
scroller.stopAnimation();
scroller.setDisabled(true);

// store beginning scale
this.startScale = this.scale;

// calculate touch midpoint relative to image viewport
this.originViewportX = (ev.touches[0].pageX + ev.touches[1].pageX) / 2 - this.element.getX();
this.originViewportY = (ev.touches[0].pageY + ev.touches[1].pageY) / 2 - this.element.getY();

// translate viewport origin to position on scaled image
this.originScaledImgX = this.originViewportX + scroller.position.x - this.translateX;
this.originScaledImgY = this.originViewportY + scroller.position.y - this.translateY;

// unscale to find origin on full size image
this.originFullImgX = this.originScaledImgX / this.scale;
this.originFullImgY = this.originScaledImgY / this.scale;

// calculate translation needed to counteract new origin and keep image in same position on screen
this.translateX += (-1 * ((this.imgWidth*(1-this.scale)) * (this.originFullImgX/this.imgWidth)));
this.translateY += (-1 * ((this.imgHeight*(1-this.scale)) * (this.originFullImgY/this.imgHeight)))

// apply new origin
this.setOrigin(this.originFullImgX, this.originFullImgY);

// apply translate and scale CSS
this.applyTransform();
}

,onImagePinch: function(ev) {
// prevent scaling to smaller than screen size
this.scale = Ext.Number.constrain(ev.scale * this.startScale, this.baseScale-2, this.getMaxScale());
this.applyTransform();
}

,onImagePinchEnd: function(ev) {

// set new translation
if(this.scale == this.baseScale)
{
// move to center
this.setTranslation(this.translateBaseX, this.translateBaseY);
}
else
{
//Resize to init size like ios
if(this.scale < this.baseScale && this.getResizeOnLoad()){
this.resetZoom();
return;
}
// calculate rescaled origin
this.originReScaledImgX = this.originScaledImgX * (this.scale / this.startScale);
this.originReScaledImgY = this.originScaledImgY * (this.scale / this.startScale);

// maintain zoom position
this.setTranslation(this.originViewportX - this.originReScaledImgX, this.originViewportY - this.originReScaledImgY);
}
// reset origin and update transform with new translation
this.setOrigin(0, 0);
this.applyTransform();




// adjust scroll container
this.adjustScroller();
}


,onZoomIn: function(){
var myScale = this.scale;
if (myScale < this.getMaxScale())
myScale = this.scale + 0.05;
if (myScale >= this.getMaxScale())
myScale = this.getMaxScale();
var ev = {pageX : 0, pageY: 0};
ev.pageX = this.viewportWidth / 2;
ev.pageY = this.viewportHeight / 2;
this.zoomImage(ev,myScale);
}

,onZoomOut: function(){
var myScale = this.scale;
if (myScale > this.baseScale)
myScale = this.scale - 0.05;
if (myScale <= this.baseScale)
myScale = this.baseScale;


var ev = {pageX : 0, pageY: 0};
ev.pageX = this.viewportWidth / 2;
ev.pageY = this.viewportHeight / 2;
this.zoomImage(ev,myScale);
}

,zoomImage: function (ev, scale, scope) {
var scroller = this.getScrollable().getScroller();
var that = this;
// zoom in toward tap position
var oldScale = this.scale
,newScale = scale
,originViewportX = ev ? (ev.pageX - this.element.getX()) : 0
,originViewportY = ev ? (ev.pageY - this.element.getY()) : 0
,originScaledImgX = originViewportX + scroller.position.x - this.translateX
,originScaledImgY = originViewportY + scroller.position.y - this.translateY
,originReScaledImgX = originScaledImgX * (newScale / oldScale)
,originReScaledImgY = originScaledImgY * (newScale / oldScale)

this.scale = newScale;
setTimeout(function(){
that.setTranslation(originViewportX - originReScaledImgX, originViewportY - originReScaledImgY);
// reset origin and update transform with new translation
//that.setOrigin(0, 0);


// reset origin and update transform with new translation
that.applyTransform();


// adjust scroll container
that.adjustScroller();

// force repaint to solve occasional iOS rendering delay
Ext.repaint();
},50)
}

,onDoubleTap: function(ev, t) {
var that = this;
var scroller = this.getScrollable().getScroller();
if(!this.getDoubleTapScale())
return false;

// set scale and translation
if(this.scale > this.baseScale)
{
// zoom out to base view
this.scale = this.baseScale;
this.setTranslation(this.translateBaseX, this.translateBaseY);
// reset origin and update transform with new translation
this.applyTransform();




// adjust scroll container
this.adjustScroller();

// force repaint to solve occasional iOS rendering delay
Ext.repaint();
}
else
{
// zoom in toward tap position
var oldScale = this.scale
,newScale = this.baseScale*4
,originViewportX = ev ? (ev.pageX - this.element.getX()) : 0
,originViewportY = ev ? (ev.pageY - this.element.getY()) : 0
,originScaledImgX = originViewportX + scroller.position.x - this.translateX
,originScaledImgY = originViewportY + scroller.position.y - this.translateY
,originReScaledImgX = originScaledImgX * (newScale / oldScale)
,originReScaledImgY = originScaledImgY * (newScale / oldScale);

this.scale = newScale;

//smoothes the transition
setTimeout(function(){
that.setTranslation(originViewportX - originReScaledImgX, originViewportY - originReScaledImgY);
// reset origin and update transform with new translation
that.applyTransform();




// adjust scroll container
that.adjustScroller();

// force repaint to solve occasional iOS rendering delay
Ext.repaint();
},50)

}


}

,setOrigin: function(x, y) {
this.imgEl.dom.style.webkitTransformOrigin = x+'px '+y+'px';
}

,setTranslation: function(translateX, translateY) {
this.translateX = translateX;
this.translateY = translateY;

// transfer negative translations to scroll offset
this.scrollX = this.scrollY = 0;

if(this.translateX < 0)
{
this.scrollX = this.translateX;
this.translateX = 0;
}
if(this.translateY < 0)
{
this.scrollY = this.translateY;
this.translateY = 0;
}
}

,resetZoom:function(){
//Resize to init size like ios
this.scale = this.baseScale;

this.setTranslation(this.translateBaseX, this.translateBaseY);

// reset origin and update transform with new translation
this.setOrigin(0, 0);
this.applyTransform();




// adjust scroll container
this.adjustScroller();

}
,resize:function(){
// get viewport size
this.viewportWidth = this.parent.element.getWidth() ||this.viewportWidth || this.getWidth();
this.viewportHeight = this.parent.element.getHeight() || this.viewportHeight || this.getHeight();




// grab image size
this.imgWidth = this.imgEl.dom.width
this.imgHeight = this.imgEl.dom.height;

// calculate and apply initial scale to fit image to screen
if(this.getResizeOnLoad()){
this.scale = this.baseScale = Math.min(this.viewportWidth/this.imgWidth, this.viewportHeight/this.imgHeight);
this.setMaxScale(this.scale*4);
}else{
this.scale = this.baseScale = 1;
}

// set initial translation to center
this.translateX = this.translateBaseX = (this.viewportWidth - this.baseScale * this.imgWidth) / 2;
this.translateY = this.translateBaseY = (this.viewportHeight - this.baseScale * this.imgHeight) / 2;

// apply initial scale and translation
this.applyTransform();

// initialize scroller configuration
this.adjustScroller();

}




,applyTransform: function() {
var fixedX = Ext.Number.toFixed(this.translateX,5)
,fixedY = Ext.Number.toFixed(this.translateY,5)
,fixedScale = Ext.Number.toFixed(this.scale, 8);

if(Ext.os.is.Android)
{
this.imgEl.dom.style.webkitTransform =
//'translate('+fixedX+'px, '+fixedY+'px)'
//+' scale('+fixedScale+','+fixedScale+')';
'matrix('+fixedScale+',0,0,'+fixedScale+','+fixedX+','+fixedY+')'
}
else
{
this.imgEl.dom.style.webkitTransform =
'translate3d('+fixedX+'px, '+fixedY+'px, 0)'
+' scale3d('+fixedScale+','+fixedScale+',1)';
}
}








,adjustScroller: function() {
var scroller = this.getScrollable().getScroller();

// disable scrolling if zoomed out completely, else enable it
if(this.scale == this.baseScale)
scroller.setDisabled(true);
else
scroller.setDisabled(false);

// size container to final image size
var boundWidth = Math.max(this.imgWidth * this.scale, this.viewportWidth);
var boundHeight = Math.max(this.imgHeight * this.scale, this.viewportHeight);




this.figEl.setStyle({
width: boundWidth + 'px'
,height: boundHeight + 'px'
});

// update scroller to new content size
scroller.refresh();




// apply scroll
var x = 0;
if(this.scrollX){
x = this.scrollX
}
var y = 0;
if(this.scrollY){
y = this.scrollY
}
scroller.scrollTo(x*-1,y*-1)
}
});

demon222
25 Apr 2012, 10:58 PM
he,

please add to config (for translation):


...
loadingMmessage: 'Loading ...'
,
...


and in initViewer




...
this.setMasked({
xtype: 'loadmask',
message:this.getLoadingMmessage()
});

...

SunboX
26 Apr 2012, 12:57 AM
two things:

1) "," on beginning of new lines looks terrible

2) you should avoid property chaining and store more object references in variables. this will speeden up thinks a bit.
for example, instead of:


onImagePinchStart: function(ev) {
var scroller = this.getScrollable().getScroller();

// disable scrolling during pinch
scroller.stopAnimation();
scroller.setDisabled(true);

// store beginning scale
this.startScale = this.scale;

// calculate touch midpoint relative to image viewport
this.originViewportX = (ev.touches[0].pageX + ev.touches[1].pageX) / 2 - this.element.getX();
this.originViewportY = (ev.touches[0].pageY + ev.touches[1].pageY) / 2 - this.element.getY();

// translate viewport origin to position on scaled image
this.originScaledImgX = this.originViewportX + scroller.position.x - this.translateX;
this.originScaledImgY = this.originViewportY + scroller.position.y - this.translateY;

// unscale to find origin on full size image
this.originFullImgX = this.originScaledImgX / this.scale;
this.originFullImgY = this.originScaledImgY / this.scale;

// calculate translation needed to counteract new origin and keep image in same position on screen
this.translateX += (-1 * ((this.imgWidth*(1-this.scale)) * (this.originFullImgX/this.imgWidth)));
this.translateY += (-1 * ((this.imgHeight*(1-this.scale)) * (this.originFullImgY/this.imgHeight)))

// apply new origin
this.setOrigin(this.originFullImgX, this.originFullImgY);

// apply translate and scale CSS
this.applyTransform();
}

you should write:


onImagePinchStart: function(ev) {
var me = this,
scroller = me.getScrollable().getScroller(),
scrollPosition = scroller.position,
touches = ev.touches,
element = me.element,
scale = me.scale;

// disable scrolling during pinch
scroller.stopAnimation();
scroller.setDisabled(true);

// store beginning scale
me.startScale = scale;

// calculate touch midpoint relative to image viewport
me.originViewportX = (touches[0].pageX + touches[1].pageX) / 2 - element.getX();
me.originViewportY = (touches[0].pageY + touches[1].pageY) / 2 - element.getY();

// translate viewport origin to position on scaled image
me.originScaledImgX = me.originViewportX + scrollPosition.x - me.translateX;
me.originScaledImgY = me.originViewportY + scrollPosition.y - me.translateY;

// unscale to find origin on full size image
me.originFullImgX = me.originScaledImgX / scale;
me.originFullImgY = me.originScaledImgY / scale;

// calculate translation needed to counteract new origin and keep image in same position on screen
me.translateX += (-1 * ((me.imgWidth * (1 - scale)) * (me.originFullImgX / me.imgWidth)));
me.translateY += (-1 * ((me.imgHeight * (1 - scale)) * (me.originFullImgY / me.imgHeight)))

// apply new origin
me.setOrigin(me.originFullImgX, me.originFullImgY);

// apply translate and scale CSS
me.applyTransform();
}

greetings Sunny

Perdiga
26 Apr 2012, 9:16 AM
he,

please add to config (for translation):


...
loadingMmessage: 'Loading ...'
,
...


and in initViewer




...
this.setMasked({
xtype: 'loadmask',
message:this.getLoadingMmessage()
});

...



I added this code


two things:

1) "," on beginning of new lines looks terrible

2) you should avoid property chaining and store more object references in variables. this will speeden up thinks a bit.
for example, instead of:


onImagePinchStart: function(ev) {
var scroller = this.getScrollable().getScroller();

// disable scrolling during pinch
scroller.stopAnimation();
scroller.setDisabled(true);

// store beginning scale
this.startScale = this.scale;

// calculate touch midpoint relative to image viewport
this.originViewportX = (ev.touches[0].pageX + ev.touches[1].pageX) / 2 - this.element.getX();
this.originViewportY = (ev.touches[0].pageY + ev.touches[1].pageY) / 2 - this.element.getY();

// translate viewport origin to position on scaled image
this.originScaledImgX = this.originViewportX + scroller.position.x - this.translateX;
this.originScaledImgY = this.originViewportY + scroller.position.y - this.translateY;

// unscale to find origin on full size image
this.originFullImgX = this.originScaledImgX / this.scale;
this.originFullImgY = this.originScaledImgY / this.scale;

// calculate translation needed to counteract new origin and keep image in same position on screen
this.translateX += (-1 * ((this.imgWidth*(1-this.scale)) * (this.originFullImgX/this.imgWidth)));
this.translateY += (-1 * ((this.imgHeight*(1-this.scale)) * (this.originFullImgY/this.imgHeight)))

// apply new origin
this.setOrigin(this.originFullImgX, this.originFullImgY);

// apply translate and scale CSS
this.applyTransform();
}

you should write:


onImagePinchStart: function(ev) {
var me = this,
scroller = me.getScrollable().getScroller(),
scrollPosition = scroller.position,
touches = ev.touches,
element = me.element,
scale = me.scale;

// disable scrolling during pinch
scroller.stopAnimation();
scroller.setDisabled(true);

// store beginning scale
me.startScale = scale;

// calculate touch midpoint relative to image viewport
me.originViewportX = (touches[0].pageX + touches[1].pageX) / 2 - element.getX();
me.originViewportY = (touches[0].pageY + touches[1].pageY) / 2 - element.getY();

// translate viewport origin to position on scaled image
me.originScaledImgX = me.originViewportX + scrollPosition.x - me.translateX;
me.originScaledImgY = me.originViewportY + scrollPosition.y - me.translateY;

// unscale to find origin on full size image
me.originFullImgX = me.originScaledImgX / scale;
me.originFullImgY = me.originScaledImgY / scale;

// calculate translation needed to counteract new origin and keep image in same position on screen
me.translateX += (-1 * ((me.imgWidth * (1 - scale)) * (me.originFullImgX / me.imgWidth)));
me.translateY += (-1 * ((me.imgHeight * (1 - scale)) * (me.originFullImgY / me.imgHeight)))

// apply new origin
me.setOrigin(me.originFullImgX, me.originFullImgY);

// apply translate and scale CSS
me.applyTransform();
}

greetings Sunny

ok, I updated the code

ImageViewer.js


Ext.define('App.Arkivus.ImageViewer',{

extend: 'Ext.Container',
config: {
doubleTapScale: 1,
maxScale: 4,
loadingMask: true,
previewSrc: false,
resizeOnLoad:true,
imageSrc: false,
initOnActivate: false,
cls: 'imageBox',
scrollable: 'both' ,
loadingMessage:'Loading...',
html: '<figure><img></figure>',
},
xtype: 'imageviewer',
initialize: function() {
if(this.initOnActivate)
this.addListener('activate', this.initViewer, this, {delay: 10, single: true});
else
this.addListener('painted', this.initViewer, this, {delay: 10, single: true});
},

initViewer: function() {
var me = this,
scroller = me.getScrollable().getScroller(),
element = me.element;

//disable scroller
scroller.setDisabled(true);

// mask image viewer
if(me.getLoadingMask())
me.setMasked({
xtype: 'loadmask',
message:me.getLoadingMessage()
});




// retrieve DOM els
me.figEl = element.down('figure');
me.imgEl = me.figEl.down('img');




// apply required styles
me.figEl.setStyle({
overflow: 'hidden',
display: 'block',
margin: 0,
});




me.imgEl.setStyle({
'-webkit-user-drag': 'none',
'-webkit-transform-origin': '0 0',
'visibility': 'hidden',
});




// show preview
if(me.getPreviewSrc())
{
element.setStyle({
backgroundImage: 'url('+me.getPreviewSrc()+')',
backgroundPosition: 'center center',
backgroundRepeat: 'no-repeat',
webkitBackgroundSize: 'contain',
});
}




// attach event listeners
me.on('load', me.onImageLoad, me);
me.imgEl.addListener({
scope: me,
doubletap: me.onDoubleTap,
pinchstart: me.onImagePinchStart,
pinch: me.onImagePinch,
pinchend: me.onImagePinchEnd,
});




// load image
if(me.getImageSrc())
me.loadImage(me.getImageSrc());
},

loadImage: function(src) {
var me = this;
if(me.imgEl){
me.imgEl.dom.src = src;
me.imgEl.dom.onload = Ext.Function.bind(me.onLoad, me, me.imgEl, 0);
}
else
me.getImageSrc() = src;
},




onLoad : function(el, e) {
var me = this;
me.fireEvent('load', me, el, e);
},

onImageLoad: function() {
var me = this,
parentElement = me.parent.element;

// get viewport size
me.viewportWidth = me.viewportWidth || me.getWidth() || parentElement.getWidth();
me.viewportHeight = me.viewportHeight || me.getHeight() || parentElement.getHeight();

// grab image size
me.imgWidth = me.imgEl.dom.width;
me.imgHeight = me.imgEl.dom.height;

// calculate and apply initial scale to fit image to screen
if(me.getResizeOnLoad()){
me.scale = me.baseScale = Math.min(me.viewportWidth/me.imgWidth, me.viewportHeight/me.imgHeight);
me.setMaxScale(me.scale*4);
}else{
me.scale = me.baseScale = 1;
}

// set initial translation to center
me.translateX = me.translateBaseX = (me.viewportWidth - me.baseScale * me.imgWidth) / 2;
me.translateY = me.translateBaseY = (me.viewportHeight - me.baseScale * me.imgHeight) / 2;

// apply initial scale and translation
me.applyTransform();

// initialize scroller configuration
me.adjustScroller();




// show image and remove mask
me.imgEl.setStyle({ visibility: 'visible' });




// remove preview
if(me.getPreviewSrc())
{
me.element.setStyle({
backgroundImage: 'none',
});
}




if(me.getLoadingMask())
me.setMasked(false);




me.fireEvent('imageLoaded', me);
},

onImagePinchStart: function(ev) {
var me = this,
scroller = me.getScrollable().getScroller(),
scrollPosition = scroller.position,
touches = ev.touches,
element = me.element,
scale = me.scale;


// disable scrolling during pinch
scroller.stopAnimation();
scroller.setDisabled(true);

// store beginning scale
me.startScale = scale;

// calculate touch midpoint relative to image viewport
me.originViewportX = (touches[0].pageX + touches[1].pageX) / 2 - element.getX();
me.originViewportY = (touches[0].pageY + touches[1].pageY) / 2 - element.getY();

// translate viewport origin to position on scaled image
me.originScaledImgX = me.originViewportX + scrollPosition.x - me.translateX;
me.originScaledImgY = me.originViewportY + scrollPosition.y - me.translateY;

// unscale to find origin on full size image
me.originFullImgX = me.originScaledImgX / scale;
me.originFullImgY = me.originScaledImgY / scale;

// calculate translation needed to counteract new origin and keep image in same position on screen
me.translateX += (-1 * ((me.imgWidth*(1-scale)) * (me.originFullImgX/me.imgWidth)));
me.translateY += (-1 * ((me.imgHeight*(1-scale)) * (me.originFullImgY/me.imgHeight)));

// apply new origin
me.setOrigin(me.originFullImgX, me.originFullImgY);

// apply translate and scale CSS
me.applyTransform();
},

onImagePinch: function(ev) {
var me = this;
// prevent scaling to smaller than screen size
me.scale = Ext.Number.constrain(ev.scale * me.startScale, me.baseScale-2, me.getMaxScale());
me.applyTransform();
},

onImagePinchEnd: function(ev) {
var me = this;

// set new translation
if(me.scale == me.baseScale)
{
// move to center
me.setTranslation(me.translateBaseX, me.translateBaseY);
}
else
{
//Resize to init size like ios
if(me.scale < me.baseScale && me.getResizeOnLoad()){
me.resetZoom();
return;
}
// calculate rescaled origin
me.originReScaledImgX = me.originScaledImgX * (me.scale / me.startScale);
me.originReScaledImgY = me.originScaledImgY * (me.scale / me.startScale);

// maintain zoom position
me.setTranslation(me.originViewportX - me.originReScaledImgX, me.originViewportY - me.originReScaledImgY);
}
// reset origin and update transform with new translation
me.setOrigin(0, 0);
me.applyTransform();




// adjust scroll container
me.adjustScroller();
},


onZoomIn: function(){
var me = this,
ev = {pageX : 0, pageY: 0},
myScale = me.scale;
if (myScale < me.getMaxScale())
myScale = me.scale + 0.05;
if (myScale >= me.getMaxScale())
myScale = me.getMaxScale();

ev.pageX = me.viewportWidth / 2;
ev.pageY = me.viewportHeight / 2;
me.zoomImage(ev,myScale);
},

onZoomOut: function(){
var me = this,
ev = {pageX : 0, pageY: 0},
myScale = me.scale;
if (myScale > me.baseScale)
myScale = me.scale - 0.05;
if (myScale <= me.baseScale)
myScale = me.baseScale;


ev.pageX = me.viewportWidth / 2;
ev.pageY = me.viewportHeight / 2;
me.zoomImage(ev,myScale);
},

zoomImage: function (ev, scale, scope) {
var me = this,
scroller = me.getScrollable().getScroller(),
scrollPosition = scroller.position,
element = me.element;

// zoom in toward tap position
var oldScale = this.scale,
newScale = scale,
originViewportX = ev ? (ev.pageX - element.getX()) : 0,
originViewportY = ev ? (ev.pageY - element.getY()) : 0,
originScaledImgX = originViewportX + scrollPosition.x - this.translateX,
originScaledImgY = originViewportY + scrollPosition.y - this.translateY,
originReScaledImgX = originScaledImgX * (newScale / oldScale),
originReScaledImgY = originScaledImgY * (newScale / oldScale);

this.scale = newScale;
setTimeout(function(){
me.setTranslation(originViewportX - originReScaledImgX, originViewportY - originReScaledImgY);
// reset origin and update transform with new translation
//that.setOrigin(0, 0);


// reset origin and update transform with new translation
me.applyTransform();


// adjust scroll container
me.adjustScroller();

// force repaint to solve occasional iOS rendering delay
Ext.repaint();
},50)
},

onDoubleTap: function(ev, t) {
var me = this,
scroller = me.getScrollable().getScroller(),
scrollPosition = scroller.position,
element = me.element;


if(!me.getDoubleTapScale())
return false;

// set scale and translation
if(me.scale > me.baseScale)
{
// zoom out to base view
me.scale = me.baseScale;
me.setTranslation(me.translateBaseX, me.translateBaseY);
// reset origin and update transform with new translation
me.applyTransform();




// adjust scroll container
me.adjustScroller();

// force repaint to solve occasional iOS rendering delay
Ext.repaint();
}else{
// zoom in toward tap position
var oldScale = me.scale,
newScale = me.baseScale*4,
originViewportX = ev ? (ev.pageX - element.getX()) : 0,
originViewportY = ev ? (ev.pageY - element.getY()) : 0,
originScaledImgX = originViewportX + scrollPosition.x - me.translateX,
originScaledImgY = originViewportY + scrollPosition.y - me.translateY,
originReScaledImgX = originScaledImgX * (newScale / oldScale),
originReScaledImgY = originScaledImgY * (newScale / oldScale);

me.scale = newScale;

//smoothes the transition
setTimeout(function(){
me.setTranslation(originViewportX - originReScaledImgX, originViewportY - originReScaledImgY);
// reset origin and update transform with new translation
me.applyTransform();




// adjust scroll container
me.adjustScroller();

// force repaint to solve occasional iOS rendering delay
Ext.repaint();
},50)

}


},

setOrigin: function(x, y) {
this.imgEl.dom.style.webkitTransformOrigin = x+'px '+y+'px';
},

setTranslation: function(translateX, translateY) {
var me = this;
me.translateX = translateX;
me.translateY = translateY;

// transfer negative translations to scroll offset
me.scrollX = me.scrollY = 0;

if(me.translateX < 0)
{
me.scrollX = me.translateX;
me.translateX = 0;
}
if(me.translateY < 0)
{
me.scrollY = me.translateY;
me.translateY = 0;
}
},

resetZoom:function(){
var me = this;
//Resize to init size like ios
me.scale = me.baseScale;

me.setTranslation(me.translateBaseX, me.translateBaseY);

// reset origin and update transform with new translation
me.setOrigin(0, 0);
me.applyTransform();


// adjust scroll container
me.adjustScroller();

},
resize:function(){
var me = this;
// get viewport size
me.viewportWidth = me.parent.element.getWidth() ||me.viewportWidth || me.getWidth();
me.viewportHeight = me.parent.element.getHeight() || me.viewportHeight || me.getHeight();




// grab image size
if(typeof(me.imgEl) != 'undefined'){
me.imgWidth = me.imgEl.dom.width;
me.imgHeight = me.imgEl.dom.height;
}else{
return;
}
// calculate and apply initial scale to fit image to screen
if(me.getResizeOnLoad()){
me.scale = me.baseScale = Math.min(me.viewportWidth/me.imgWidth, me.viewportHeight/me.imgHeight);
me.setMaxScale(me.scale*4);
}else{
me.scale = me.baseScale = 1;
}

// set initial translation to center
me.translateX = me.translateBaseX = (me.viewportWidth - me.baseScale * me.imgWidth) / 2;
me.translateY = me.translateBaseY = (me.viewportHeight - me.baseScale * me.imgHeight) / 2;

// apply initial scale and translation
me.applyTransform();

// initialize scroller configuration
me.adjustScroller();

},




applyTransform: function() {
var me = this,
fixedX = Ext.Number.toFixed(me.translateX,5),
fixedY = Ext.Number.toFixed(me.translateY,5),
fixedScale = Ext.Number.toFixed(me.scale, 8);

if(Ext.os.is.Android)
{
me.imgEl.dom.style.webkitTransform =
//'translate('+fixedX+'px, '+fixedY+'px)'
//+' scale('+fixedScale+','+fixedScale+')';
'matrix('+fixedScale+',0,0,'+fixedScale+','+fixedX+','+fixedY+')'
}
else
{
me.imgEl.dom.style.webkitTransform =
'translate3d('+fixedX+'px, '+fixedY+'px, 0)'
+' scale3d('+fixedScale+','+fixedScale+',1)';
}
},


adjustScroller: function() {
var me = this,
scroller = me.getScrollable().getScroller(),
scale = me.scale;

// disable scrolling if zoomed out completely, else enable it
if(scale == me.baseScale)
scroller.setDisabled(true);
else
scroller.setDisabled(false);

// size container to final image size
var boundWidth = Math.max(me.imgWidth * scale, me.viewportWidth);
var boundHeight = Math.max(me.imgHeight * scale, me.viewportHeight);




me.figEl.setStyle({
width: boundWidth + 'px',
height: boundHeight + 'px',
});

// update scroller to new content size
scroller.refresh();




// apply scroll
var x = 0;
if(me.scrollX){
x = me.scrollX
}
var y = 0;
if(me.scrollY){
y = me.scrollY
}
scroller.scrollTo(x*-1,y*-1)
},
});


the sample
code result in Sencha Fiddle
http://www.senchafiddle.com/#opdT7
full screen result
http://www.senchafiddle.com/full/!opdT7/

SunboX
26 Apr 2012, 11:19 PM
looks much better, really nice now. :o)

themightychris
29 Apr 2012, 4:42 PM
Some attribution would be cool if you're going to rename my component

pepperseb
10 May 2012, 12:35 AM
I had an issue when I got a src but the image didn't exist on the server so an endless loading mask was displayed, which didn't meet my goal.

Indeed, I prefer displaying an image 'No image available' rather than an endless loading that makes users think the connection is lost

So, I dived into this code and added this single line:



if(me.imgEl){
me.imgEl.dom.src = src;
me.imgEl.dom.onload = Ext.Function.bind(me.onLoad, me, me.imgEl, 0);
me.imgEl.dom.onerror = function() {
this.src = 'http://yourdomain/no-image.png';
};
}


Hope this helps

armode
10 May 2012, 3:20 AM
That's a good idea, pepperseb, I added that...

There's another issue in the resize function for orientationchange; if you first zoom a liitle bit and after that do the orientationchange, the image is not at the right postion!
I just added the resetZoom() at the end and now it works fine for me:



resize: function () {
var me = this;
// get viewport size
me.viewportWidth = me.parent.element.getWidth() || me.viewportWidth || me.getWidth();
me.viewportHeight = me.parent.element.getHeight() || me.viewportHeight || me.getHeight();

// grab image size
if (typeof (me.imgEl) != 'undefined') {
me.imgWidth = me.imgEl.dom.width;
me.imgHeight = me.imgEl.dom.height;
} else {
return;
}
// calculate and apply initial scale to fit image to screen
if (me.getResizeOnLoad()) {
me.scale = me.baseScale = Math.min(me.viewportWidth / me.imgWidth, me.viewportHeight / me.imgHeight);
me.setMaxScale(me.scale * 4);
} else {
me.scale = me.baseScale = 1;
}

// set initial translation to center
me.translateX = me.translateBaseX = (me.viewportWidth - me.baseScale * me.imgWidth) / 2;
me.translateY = me.translateBaseY = (me.viewportHeight - me.baseScale * me.imgHeight) / 2;

me.resetZoom();

},

Perdiga
10 May 2012, 9:42 AM
nice ..


I did two methods one for load and another to unload the image.
i did this to optimize memory in carousel.



loadImage: function(src) {
var me = this;
if(me.imgEl){
me.imgEl.dom.src = src;
me.imgEl.dom.onload = Ext.Function.bind(me.onLoad, me, me.imgEl, 0);
// me.imgEl.dom.onerror = function() {
// this.src = '../../../resources/images/noimage.jpg';
// };
}


else
me.setImageSrc(src);
},


unloadImage: function() {
var me = this;


// mask image viewer
if(me.getLoadingMask())
me.setMasked({
xtype: 'loadmask',
message:me.getLoadingMessage()
});


if(me.imgEl){
me.imgEl.dom.src = '';
me.imgEl.setStyle({ visibility: 'hidden' });
}
else{
me.setImageSrc('');
me.imgEl.setStyle({ visibility: 'hidden' });
}
},

pepperseb
11 May 2012, 3:17 AM
Do you guys know how to disable image switching when current image is zommed in?

I'm having a huge headache :((

Perdiga
11 May 2012, 9:27 AM
i think that you you can use
me.imgEl.setStyle({ visibility: 'hidden' });
or
me.imgEl.setStyle({ disabled: 'true' });

demon222
11 May 2012, 2:36 PM
Pretty please - do the update in one place and overall

R

pepperseb
14 May 2012, 11:30 PM
i think that you you can use
me.imgEl.setStyle({ visibility: 'hidden' });
or
me.imgEl.setStyle({ disabled: 'true' });






No it doesn't work. I also tried to get the carousel with getParent() but I coundn't find any methods to stop switching image...

Actually I'm quite surprise that nobody asked for this because the imageviewer doesn't work properly for me when the current image is zoomed in. What's happening? If I try to scroll horizontally a llitle bit too fast, when image is zoomed in, the current image is switched.

35226

montymccune
15 May 2012, 11:24 AM
Is there a trick to just getting an image to load? My simple implementation....




Ext.define("PhoenixTouch.view.Xray", {
extend: 'Ext.Container',


requires:['PhoenixTouch.view.PinchZoomContainer',
'PhoenixTouch.view.XrayThumbnailSlider',
'Ext.mixin.Observable',
'
Arkivus
.ImageViewer'],

xtype: 'xray',


config: {


layout: 'fit',


items: [
{
xtype: 'imageviewer',
imgSrc:'https://192.168.0.99/phoenix/xrays/PAT1000000021/1.2.392.200036.9125.2.691113118120.64559415338.1668133/J1.2.392.200036.9125.9.0.118444256.821560832.1901820022.jpg',
}
]
}
});






The link is legit - I can navigate to in in Chrome. Also, if I dont set imgSrc in config, and then later try to set the image in the controller via loadImage i get "invalid left-hand assignment"...




,loadImage: function(src) {
if(this.imgEl){
this.imgEl.dom.src = src;
this.imgEl.dom.onload = Ext.Function.bind(this.onLoad, this, this.imgEl, 0);
}
else
this.getImageSrc() = src; <------ right herehttp://www.sencha.com/forum/chrome-devtools://devtools/Images/errorIcon.pngUncaught ReferenceError: Invalid left-hand side in assignment



}

armode
15 May 2012, 11:27 PM
Why don't you add the imageviewer component via xtype where you need it?


...
items: [{
xtype: 'imageviewer',
imageSrc: 'https://192.168.0.99/phoenix/xrays/PAT1000000021/...',
}]


You can look at the examples from Chris (https://github.com/JarvusInnovations/Jarvus.mobile.PinchCarousel), too, who wrote the component for ST1...

montymccune
16 May 2012, 5:27 AM
see above post... I dont see how you're suggestion differs from what I did? Am I missing something?

thanks for the quick reply, monty


Why don't you add the imageviewer component via xtype where you need it?


...
items: [{
xtype: 'imageviewer',
imageSrc: 'https://192.168.0.99/phoenix/xrays/PAT1000000021/...',
}]


You can look at the examples from Chris (https://github.com/JarvusInnovations/Jarvus.mobile.PinchCarousel), too, who wrote the component for ST1...

pepperseb
16 May 2012, 5:41 AM
I can see that you put imgSrc instead of imageSrc

montymccune
16 May 2012, 6:10 AM
I can see that you put imgSrc instead of imageSrc


wow, you really have to pay attention with this language :D

thanks tons - made my day!

montymccune
16 May 2012, 6:27 AM
So I still have one issue - trying to dynamically load images into the imageSrc. All the examples I have seen so far have been statically loaded. I have tried to use the loadImage method but it gives me a "Uncaught ReferenceError: Invalid left-hand side in assignment" error. Is there a way to modify this to load the images from a list of thumbnails? I am not using this as a carousel, just a single image viewer. I DO have the thumbnail list already. Any help would be much appreciated!

monty

Gaelmart
17 May 2012, 6:51 AM
Similar Question. How to load images dynamically, but I'm in an override file as I'm using Sencha Architect i.e.


Ext.define('BoilerShop.OverrideDiagramCarousel', {
override: 'BoilerShop.view.DiagramCarousel',
config: {

items: [
{
xtype: 'imageviewer',
style: {
backgroundColor: '#222'
},
imageSrc: 'http://www.ibasis.co.uk/Uploads/SAUNIER DUVAL/1281301.png'
},
{
xtype: 'imageviewer',
style: {
backgroundColor: '#222'
},
imageSrc: 'http://www.ibasis.co.uk/Uploads/SAUNIER DUVAL/1281302.png'
},
{
xtype: 'imageviewer',
style: {
backgroundColor: '#222'
},
imageSrc: 'http://www.ibasis.co.uk/Uploads/SAUNIER DUVAL/1281303.png'
},
{
xtype: 'imageviewer',
style: {
backgroundColor: '#222'
},
imageSrc: 'http://www.ibasis.co.uk/Uploads/SAUNIER DUVAL/1281304.png'
},
{
xtype: 'imageviewer',
style: {
backgroundColor: '#222'
},
imageSrc: 'http://www.ibasis.co.uk/Uploads/SAUNIER DUVAL/1281305.png'
}

]

},
constructor: function (config) {
this.callParent(arguments); // calls Ext.tip.ToolTip's constructor
alert('This gets shown so were ok here');
}

});

umbro77
23 May 2012, 5:05 AM
No it doesn't work. I also tried to get the carousel with getParent() but I coundn't find any methods to stop switching image...

Actually I'm quite surprise that nobody asked for this because the imageviewer doesn't work properly for me when the current image is zoomed in. What's happening? If I try to scroll horizontally a llitle bit too fast, when image is zoomed in, the current image is switched.


You have to add the following code to your Carousel component:


onDragStart: function (e) {
var scroller = this.getActiveItem().getScrollable().getScroller();
if (e.targetTouches.length == 1 && (e.deltaX < 0 && scroller.getMaxPosition().x === scroller.position.x) || (e.deltaX > 0 && scroller.position.x == 0)) {
this.callParent(arguments);
}
},
onDrag: function (e) {
if (e.targetTouches.length == 1)
this.callParent(arguments);
},
onDragEnd: function (e) {
if (e.targetTouches.length < 2)
this.callParent(arguments);
}

umbro77
23 May 2012, 6:31 AM
I've disabled the carousel switch while the image is zoomed because the previous code doesn't work as expected.

My solution:



onDragStart: function (e) {
if(this.getActiveItem().scale < 1) {
this.callParent(arguments);
}
},

pepperseb
25 May 2012, 12:13 AM
Ok guys, this is my improvement to prevent switching between images when active image is zoomed in.

Thanks umbro77 for giving me some hints.

In the imageviewer:

Add


config: {
...,
isZoomed: false
...
}


Add two lines in onDoubleTap function:


onDoubleTap: function(ev, t) {
var me = this,
scroller = me.getScrollable().getScroller(),
scrollPosition = scroller.position,
element = me.element;


if(!me.getDoubleTapScale())
return false;

// set scale and translation
if(me.scale > me.baseScale) {
// ZOOM OUT to base view
me.setIsZoomed(false);
me.scale = me.baseScale;
me.setTranslation(me.translateBaseX, me.translateBaseY);
// reset origin and update transform with new translation
me.applyTransform();


// adjust scroll container
me.adjustScroller();

// force repaint to solve occasional iOS rendering delay
Ext.repaint();
}
else {
// ZOOM IN toward tap position
me.setIsZoomed(true);
var oldScale = me.scale,
newScale = me.baseScale * me.getZoomRatio(),
originViewportX = ev ? (ev.pageX - element.getX()) : 0,
originViewportY = ev ? (ev.pageY - element.getY()) : 0,
originScaledImgX = originViewportX + scrollPosition.x - me.translateX,
originScaledImgY = originViewportY + scrollPosition.y - me.translateY,
originReScaledImgX = originScaledImgX * (newScale / oldScale),
originReScaledImgY = originScaledImgY * (newScale / oldScale);

me.scale = newScale;

//smoothes the transition
setTimeout(function(){
me.setTranslation(originViewportX - originReScaledImgX, originViewportY - originReScaledImgY);
// reset origin and update transform with new translation
me.applyTransform();


// adjust scroll container
me.adjustScroller();

// force repaint to solve occasional iOS rendering delay
Ext.repaint();
},50)
}
},


In your carousel, you should have a onDragStart function (line 343 for me), just add:


onDragStart: function(e) {
// if current image is zoomed in, stop switching
if (this.getActiveItem().getIsZoomed()) {
e.stopPropagation();
return;
}
var direction = this.getDirection(),
absDeltaX = e.absDeltaX,
absDeltaY = e.absDeltaY,
directionLock = this.getDirectionLock();

....



Hope this helps!!!

SunboX
31 May 2012, 7:04 AM
Could someone please put all those "I optimized this" and "I fixed that" code togehter in one slideshow class? And maybe, host that class somewhere togehter with an example?

thx Sunny

michelerota77
5 Jun 2012, 2:45 PM
If you put the carousel inside a nestedList as a detailCard, it works only the first time.

To fix, i changed the ImageCarousel activeitemchange and the activate listeners.
Note the "container.getScrollable()" in "activeitemchange" and "component.setActiveItem(0)" in "activate"



listeners : {
activeitemchange: function(container, value, oldValue, eOpts){
if(container.getScrollable() && oldValue){
oldValue.resetZoom();
this.getActiveItem().resize();
}
},

resize: function(component, eOpts){
this.getActiveItem().resize();
},

activate: function(component){
component.setActiveItem(0);
}
}

phimaur
5 Jun 2012, 10:25 PM
Nice work.
On my ipad, at the end of a pinch/zoom gesture, the image disappears and reappears very fast.
Is there a way to avoid that?
Thanks

Jamesaya
20 Jun 2012, 11:01 PM
You did amazing images component.

Is there any possibility let the HTML contents can be zoom in/out like images?

contech
17 Aug 2012, 5:17 AM
Hey,

ImageViewer#onImageLoad if this.viewportWidth > this.baseScale * this.imgWidth, translateX and translateBaseX will be negativ and the image will be cut off. #setTransition use the < 0 evaluation and works correct so I changed the lines:



// set initial translation to center
this.translateX = this.translateBaseX = (this.viewportWidth - this.baseScale * this.imgWidth) / 2;
this.translateY = this.translateBaseY = (this.viewportHeight - this.baseScale * this.imgHeight) / 2;

to:


// calc initial translation
var tmpTranslateX = (this.viewportWidth - this.baseScale * this.imgWidth) / 2;
var tmpTranslateY = (this.viewportHeight - this.baseScale * this.imgHeight) / 2;


// set initial translation to center
this.setTranslation(tmpTranslateX, tmpTranslateY);
this.translateBaseX = this.translateX;
this.translateBaseY = this.translateY;


That works for me :-)

armode
20 Aug 2012, 12:28 AM
Hi contech

thanks for your suggestion!
I can't find any case where the translate variables are getting < 0 on load?
In my code it looks like that this case is not possible, because of:


me.baseScale = Math.min(me.viewportWidth/me.imgWidth, me.viewportHeight/me.imgHeight);

Maybe you doesn't use the latest version of this component? You don't use the perfomance optimisation with coping the scope into the me variable...

jeroenwalter
23 Aug 2012, 4:51 AM
Don't read this the wrong way, I use this component (with my own modifications) but keeping up with all changes here is hard.
You refer to the latest version, so what would that be?
This thread continually posts some version and separate fixes all over the place.
If someone would be so nice as to make a github repository or such for this component, then development could be more streamlined imo.

allisterf
24 Aug 2012, 2:10 AM
I think many people are asking the same thing, Jeroen. The thread has become so complicated and diverse that the majority have little or no chance of geting this component going. You suggest putting something on GitHub - great idea - and as you seem to have a working version, any chance you can get the ball rolling and we could start with that...?

allister

jeroenwalter
24 Aug 2012, 2:17 AM
My version already is on Github.
It is part of my comic reader web app.
You can find it here https://github.com/jeroenwalter/Badaap-Comic-Reader/blob/master/app/view/ImageViewer.js

It is however modified for my own use so it fits better in my project. It is also based on a version from a few months back.

Maybe I will create a new repository for it, because I haven't changed that much and I think the changes I made may be useful to others.

However, I'm quite pleased with how it is working right now, so I don't plan to work on it until I need something fixed or have to add a new feature.

Right now my focus is on making the web app as a whole better. I'm in the process of rewriting the whole comic reader so it will be a plugin for ComicRack.
For details you may take a look at http://www.badaap.nl/wordpress/badaap-comic-reader-integrated-with-comicrack-web-viewer/

SunboX
24 Aug 2012, 2:21 AM
If you are interested, I can put it on github. Together with some examples/testcases.

greetings Sunny

jeroenwalter
24 Aug 2012, 2:25 AM
If you are interested, I can put it on github. Together with some examples/testcases.

greetings Sunny

That would be awesome, as my version on github has no special testcases, it's just part of a big app.

allisterf
24 Aug 2012, 2:30 AM
That would be brilliant Sunny! Thanks so much!!
Allister

SunboX
24 Aug 2012, 3:53 AM
Ok, n.p. I will write some demos/tests this evening. Will post a link here, if itīs online.

SunboX
24 Aug 2012, 3:03 PM
Ok, here we go. Please fork it and make it more awesome! ;o)

Github Repository with latest cleaned-up(!) Code:
https://github.com/SunboX/ST2_ImageViewer

greetings Sunny

jeroenwalter
24 Aug 2012, 3:04 PM
Thanks ! ... and forked !

Bukurov Alex
12 Sep 2012, 8:00 PM
Pinch event doesn't work in native android application

sogorman
25 Sep 2012, 8:53 AM
Has anyone had any luck adding this into a panel? I am trying to incorporate it using the code below and no errors are thrown but nothing displays. I have also verified that the path to the require is valid but again nothing...


Ext.define('BJ.view.Eventmaps',{ requires: ['Ext.ux.ImageViewer'],
extend: 'Ext.Panel',
xtype: 'eventmaps',
config: {
title: 'eventmaps',
xtype: 'panel',
items:[{
xtype: 'imageviewer',
style: {
backgroundColor: '#333'
},
imageSrc: 'http://farm8.staticflickr.com/7242/7220454816_7972682ea1_o.jpg'

}]
}
});

SunboX
25 Sep 2012, 9:32 AM
You should create a complete example showing the failure by using http://www.senchafiddle.com/ or so. Than we can try to fix it.You code looks ok. Maybe too much panels inside panels and missing layouts. But can't tell you, why it's not visible.

amitthakkar
18 Apr 2013, 2:10 AM
Hi,

i am actually building a carousel of thumbnails and upon clicking it the image shows up in a modal panel which allows pinch to zoom and translations.

the pinch to zoom works perfectly in a normal container, but once i make it modal, the pinch doesn't work.


Ext.Loader.setConfig({
enabled: true,
paths: {
'Ext.ux': '../../ux'
}
});

Ext.application({

name : 'Simple ImageViewer Demo',
views : [
'Ext.ux.ImageViewer'
],
launch: function() {

var container = Ext.create('Ext.Container',{
height:'100%',
width:'100%',
modal:true,
items: [
{
xtype: 'imageviewer',
style: {
backgroundColor: '#333'
},
modal:true,
height:'99%',
width:'100%',
imageSrc: 'http://farm8.staticflickr.com/7242/7220454816_7972682ea1_o.jpg'
}
]
});

Ext.Viewport.add(container);






}
});

Any help is appreciated. Thank you.

amitthakkar
18 Apr 2013, 2:31 AM
As pointed out above my sogorman, When you added the imageviewer control to a panel or a container it doesn't show.

i too faced the same problem.

i had to make the the imageviewer control modal property as true OR set top:1 for the image to show.

But once the image show, the drag, scrollers work as expected but the pinch to zoom doesn't work.


Ext.Loader.setConfig({
enabled: true,
paths: {
'Ext.ux': '../../ux'
}
});

Ext.application({

name : 'Simple ImageViewer Demo',
views : [
'Ext.ux.ImageViewer'
],
launch: function() {

var container = Ext.create('Ext.Panel',{
height:'100%',
width:'100%',
// modal:true,
items: [
{
xtype: 'imageviewer',
style: {
backgroundColor: '#333'
},
modal:true,
height:'99%',
width:'100%',
imageSrc: 'http://farm8.staticflickr.com/7242/7220454816_7972682ea1_o.jpg'
}
]
});

Ext.Viewport.add(container);






}
});

evegraphic
30 May 2013, 12:50 AM
Hi everybody !

You're class is very useful. I tried it in a carousel and it works well if we want only one image per slide.
But, as soon as we want 2 images per slide, it doesn't work any more.

To have 2 images per slide, i added a container with a hbox layout which contains two 'imageviewer". So, my carousel hasn't an imageviewer child directly but a container with 2 items.



xtype: 'container',
layout: 'hbox',
items: [
{
xtype: 'imageviewer',
imageSrc: 'url picture 1',
},
{
xtype: 'imageviewer',
imageSrc: 'url picture 2',
}
]


Could you help me to modify you're class ImageViewer.js in order to make work this structure ?
Thanks in advance.

schaudhry123
12 Jul 2013, 8:37 AM
Does anyone else have the problem of whenever the screen is rotated, the image is only partially on the screen initially before jumping back to its normal spot?

armode
16 Jul 2013, 6:45 AM
Does anyone else have the problem of whenever the screen is rotated, the image is only partially on the screen initially before jumping back to its normal spot?

Do you mean the rotating just isn't smooth like this:
https://www.dropbox.com/s/931nv0fw1ggfd0f/PinchImg Rotating not smooth.png
The second pic in the middle shows the img before resizing to new screen dimensions...

kisscool82
3 Sep 2013, 7:18 AM
Hi !

I use this wonderfull class in my project.
I load multiple imageviewers in a lasy carousel, then I can "read" a book. Each page is a jpg and i can zoom in and out.
lazy carousel : https://github.com/cburgdorf/sencha-playground/tree/gh-pages/lazy-infinite-carousel

It works great.
I run the app with cordova and sometimes, xcode receive memory warning and my app crashes.
If I remove image viewer and replace it with simple image class in my lazy carousel, everything works fine.

Memory warnings occure before I zoom in so I don't think the css transform is the cause.
Does anyone has an idea please ?