Skip to content

Instantly share code, notes, and snippets.

@vazad28
Last active September 30, 2024 18:26
Show Gist options
  • Save vazad28/bd7ff445b090ab130ff1b291ca057002 to your computer and use it in GitHub Desktop.
Save vazad28/bd7ff445b090ab130ff1b291ca057002 to your computer and use it in GitHub Desktop.
Page code for image pinch and zoom in ionic RC3. I used code from multiple places and credit is due. I cant seem to find the pages I have used the code from. If you know, please tell me so I can add that here.
<ion-header no-shadow>
<ion-navbar no-border-bottom>
<ion-buttons start>
<button ion-button color="light" (click)="closeModal()">Cancel</button>
</ion-buttons>
<ion-title>Media</ion-title>
<ion-buttons end>
<ion-spinner *ngIf="!mediaLoaded" color="light"></ion-spinner>
</ion-buttons>
</ion-navbar>
</ion-header>
<ion-content>
<div #imageParent class="pinch-zoom-container">
<img #image dimg="medium" class="pinch-zoom-image" [src]="src" alt="loading.." (load)="setMediaLoaded()">
</div>
</ion-content>
.scroll-content {
background: #1e1e1e;
}
ion-navbar .toolbar-background {
background: rgba(0,0,0,0.3);
}
ion-content .scroll-content {
margin-top:0px !important;
}
.pinch-zoom-container {
position:relative;
overflow: hidden;
height: 100%;
width:100%;
}
.pinch-zoom-image {
position: absolute;
top: 50%; /* position the top edge of the element at the middle of the parent */
left: 50%; /* position the left edge of the element at the middle of the parent */
transform: translate(-50%, -50%); /* This is a shorthand of
translateX(-50%) and translateY(-50%) */
width: 100%;
}
import { Component, ViewChild } from '@angular/core';
import { Platform, NavController, NavParams, ViewController } from 'ionic-angular';
import { Gesture } from 'ionic-angular'
@Component({
selector: 'page-image-zoom',
templateUrl: 'image-zoom.html'
})
export class ImageZoom {
@ViewChild('image') element;
@ViewChild('imageParent') elementParent;
image = null;
container = null;
transforms = [];
adjustScale = 1;
adjustDeltaX = 0;
adjustDeltaY = 0;
currentScale = null;
currentDeltaX = null;
currentDeltaY = null;
public media: any;
public src: string;
public mediaType: string;
private gesture: Gesture;
public mediaLoaded:boolean = false;
constructor(
public platform: Platform,
public navCtrl: NavController,
public viewCtrl: ViewController
) {
this.media = this.navParams.get("media");
this.src = this.appGlobals.mediaBaseUrls.medium + this.media.id + '.jpg';
console.log("src", this.src);
}
setMediaLoaded =() =>{
setTimeout(()=>this.mediaLoaded = true, 200);
}
ionViewDidLoad() {
this.image = this.element.nativeElement;
this.container = this.elementParent.nativeElement;
// Prevent long press saving on mobiles.
this.container.addEventListener('touchstart', function(e) {
e.preventDefault();
});
this.init();
}
/*
Initialize listeners for gestures
*/
init = () => {
//create gesture obj w/ ref to DOM element
this.gesture = new Gesture(this.element.nativeElement);
//listen for the gesture
this.gesture.listen();
this.gesture.on('doubletap', (ev) => {
this.transforms = [];
this.adjustScale += 1;
if (this.adjustScale >= 4) this.adjustScale = 1;
this.transforms.push('scale(' + this.adjustScale + ')');
this.container.style.transform = this.transforms.join(' ');
});
this.gesture.on("pinch", (ev) => {
this.transforms = [];
// Adjusting the current pinch/pan event properties using the previous ones set when they finished touching
this.currentScale = this.adjustScale * ev.scale;
this.currentDeltaX = this.adjustDeltaX + (ev.deltaX / this.currentScale);
this.currentDeltaY = this.adjustDeltaY + (ev.deltaY / this.currentScale);
// Concatinating and applying parameters.
if (this.currentScale < 1) {
this.currentScale = 1;
this.currentDeltaX = 0;
this.currentDeltaY = 0;
}
this.transforms.push('scale(' + this.currentScale + ')');
this.transforms.push('translate(' + this.currentDeltaX + 'px,' + this.currentDeltaY + 'px)');
this.container.style.transform = this.transforms.join(' ');
});
this.gesture.on("pinchend", (ev) => {
// Saving the final transforms for adjustment next time the user interacts.
this.adjustScale = this.currentScale;
this.adjustDeltaX = this.currentDeltaX;
this.adjustDeltaY = this.currentDeltaY;
});
this.gesture.on("panend", (ev) => {
// Saving the final transforms for adjustment next time the user interacts.
this.adjustScale = this.currentScale;
this.adjustDeltaX = this.currentDeltaX;
this.adjustDeltaY = this.currentDeltaY;
});
}
/* close modal */
closeModal() {
this.viewCtrl.dismiss();
}
}
@hrafven
Copy link

hrafven commented Jun 15, 2018

Hi @vazad28 ,
I think you are missing

public navParams: NavParams

in the constructor's parameters

@jcalvezar
Copy link

Hi @vazad28 ,
Thanks for the code, im using it, its very good :)
Hrafven is right, navParms should be injected.
And I cant move the image using just one finger, I have to use two to zoom/shring and to move.
Can you modify it to let one move the image using just one finger please?
Thanks !

@addkr
Copy link

addkr commented Jul 24, 2018

@jcalvezar you just copy paste this code inside the "init" function:

this.gesture.on("pan", (ev) => {
this.transforms = [];
// Adjusting the current pinch/pan event properties using the previous ones set when they finished touching
this.currentScale = this.adjustScale * ev.scale;
this.currentDeltaX = this.adjustDeltaX + (ev.deltaX / this.currentScale);
this.currentDeltaY = this.adjustDeltaY + (ev.deltaY / this.currentScale);
if (this.currentScale < 1) {
this.currentScale = 1;
this.currentDeltaX = 0;
this.currentDeltaY = 0;
}
this.transforms.push('scale(' + this.currentScale + ')');
this.transforms.push('translate(' + this.currentDeltaX + 'px,' + this.currentDeltaY + 'px)');
this.container.style.transform = this.transforms.join(' ');
});

Guess @vazad28 forgot to add this one, it work the same as the function for pinch.

@Pringels300
Copy link

Pringels300 commented Aug 1, 2018

Hello, first, I would like to thank you for sharing this code.
I have a question. Doesn't this work with an Ngfor img src? Background: I want to open a base64 from my database and then mark a location via touch (XY coordinates).
I get this error when entering to the Page "can not get native element of undefined" If i click ok I still get the picture displayed, but have no access to the gestures.

I would be really grateful for help!

<ion-header>
  <ion-navbar>
      <ion-title text-center>
        </ion-title>
</ion-navbar>
</ion-header>


<ion-content>
> >    
> >     <div #imageParent class="pinch-zoom-container
> > 
> >       <ion-card #canvas *ngFor="let maps of this.mangel.maps2; let i=index">
> >         <img #image dimg="medium" class="pinch-zoom-image" src="data:image/jpg;base64,{{maps.base64}}" *ngIf="maps.base64" />
> >         </ion-card>   
> >       
> >       </div> "
> 
</ion-content>
 import { NavParams} from 'ionic-angular';
import { Component, ViewChild, ElementRef, Renderer } from '@angular/core';
import { NavController, Gesture, Content,Platform,ViewController} from 'ionic-angular';
import { ScreenOrientation } from '../../../node_modules/@ionic-native/screen-orientation';

@Component({
  selector: 'page-openplan',
  templateUrl: 'openplan.html',
})
export class OpenplanPage {
  
  map_id;
  private _CANVAS  : any;
  private _CONTEXT : any;
  canvasElement:any;

  image = null;
  container = null;
  transforms = [];
  adjustScale = 1;
  adjustDeltaX = 0;
  adjustDeltaY = 0;

  currentScale = null;
  currentDeltaX = null;
  currentDeltaY = null;

  public media: any;
  public mediaType: string;
  public src: string;
  private gesture: Gesture;
  public mediaLoaded:boolean = false;

  @ViewChild('image') element;
  @ViewChild('imageParent') elementParent;

    constructor(
      public navCtrl: NavController, 
      public navParams: NavParams,
      private screenOrient: ScreenOrientation,
      private renderer: Renderer,
      private mangel: MangelProvider,
      private platform: Platform,
      private viewCtrl: ViewController,  
    ) 
    {
      this.map_id = this.navParams.get("map_id")  
    }

    ionViewDidLoad() {
      this.image = this.element.nativeElement;
      this.container = this.elementParent.nativeElement;
      // Prevent long press saving on mobiles.
      this.container.addEventListener('touchstart', function(e) {
        e.preventDefault();
      });
  
  this.init();

      this.screenOrient.lock(this.screenOrient.ORIENTATIONS.LANDSCAPE)
      this.mangel.getMaps2(this.map_id)
      
    }
  
    ionViewWillEnter() {
      this.screenOrient.lock(this.screenOrient.ORIENTATIONS.LANDSCAPE)
      this.mangel.getMaps2(this.map_id)

    } 

    init = () => {
      //create gesture obj w/ ref to DOM element
      this.gesture = new Gesture(this.element.nativeElement);
  
      //listen for the gesture
      this.gesture.listen();

      this.gesture.on("pan", (ev) => {
        this.transforms = [];
        // Adjusting the current pinch/pan event properties using the previous ones set when they finished touching
        this.currentScale = this.adjustScale * ev.scale;
        this.currentDeltaX = this.adjustDeltaX + (ev.deltaX / this.currentScale);
        this.currentDeltaY = this.adjustDeltaY + (ev.deltaY / this.currentScale);
        if (this.currentScale < 1) {
        this.currentScale = 1;
        this.currentDeltaX = 0;
        this.currentDeltaY = 0;
        }
        this.transforms.push('scale(' + this.currentScale + ')');
        this.transforms.push('translate(' + this.currentDeltaX + 'px,' + this.currentDeltaY + 'px)');
        this.container.style.transform = this.transforms.join(' ');
        });
  
      this.gesture.on('doubletap', (ev) => {
        this.transforms = [];
        this.adjustScale += 1;
        if (this.adjustScale >= 4) this.adjustScale = 1;
        this.transforms.push('scale(' + this.adjustScale + ')');
        this.container.style.transform = this.transforms.join(' ');
      });
  
  
      this.gesture.on("pinch", (ev) => {
  
        this.transforms = [];
  
        // Adjusting the current pinch/pan event properties using the previous ones set when they finished touching
        this.currentScale = this.adjustScale * ev.scale;
        this.currentDeltaX = this.adjustDeltaX + (ev.deltaX / this.currentScale);
        this.currentDeltaY = this.adjustDeltaY + (ev.deltaY / this.currentScale);
  
        // Concatinating and applying parameters.
        if (this.currentScale < 1) {
          this.currentScale = 1;
          this.currentDeltaX = 0;
          this.currentDeltaY = 0;
        }
        this.transforms.push('scale(' + this.currentScale + ')');
        this.transforms.push('translate(' + this.currentDeltaX + 'px,' + this.currentDeltaY + 'px)');
        this.container.style.transform = this.transforms.join(' ');
  
      });
  
  
      this.gesture.on("pinchend", (ev) => {
  
        // Saving the final transforms for adjustment next time the user interacts.
        this.adjustScale = this.currentScale;
        this.adjustDeltaX = this.currentDeltaX;
        this.adjustDeltaY = this.currentDeltaY;
  
      });
  
      this.gesture.on("panend", (ev) => {
  
        // Saving the final transforms for adjustment next time the user interacts.
        this.adjustScale = this.currentScale;
        this.adjustDeltaX = this.currentDeltaX;
        this.adjustDeltaY = this.currentDeltaY;
  
      });
  
    }
  
    /* close modal */
    closeModal() {
      this.viewCtrl.dismiss();
  }

   }



@saurabh-kale
Copy link

Can someone please elaborate on the appGlobals from the code in the constructor, I am getting an error for it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment