I implemented the drawing feature on canvas using fabric js in angular. all things works perfect for me. but Now I have to add canvas zoom and pan options using fabric js. for that I refer this fabricjs example.
Zoom and Pan option working on Mouse Event there is no issue. but when I’m using Touch Devices it not works.
see below code what I tried.
import {
AfterViewInit,
Component,
ElementRef,
VERSION,
ViewChild,
} from '@angular/core';
import { fabric } from 'fabric';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent implements AfterViewInit {
version = VERSION.full;
@ViewChild('mainHtmlCanvas') mainHtmlCanvas!: ElementRef;
mainCanvas!: fabric.Canvas;
isDragging: boolean = false;
selection: boolean = true;
lastPosX!: number;
lastPosY!: number;
isDrawingMode: boolean = false;
ngAfterViewInit() {
this.mainCanvas = new fabric.Canvas(this.mainHtmlCanvas.nativeElement, {
hoverCursor: 'pointer',
selection: this.selection,
selectionBorderColor: 'blue',
width: 800,
height: 500,
allowTouchScrolling: true,
isDrawingMode: this.isDrawingMode,
backgroundColor: '#eee',
});
const rect = new fabric.Rect({
left: 100,
top: 100,
fill: 'red',
width: 50,
height: 100,
});
this.mainCanvas.add(rect);
// this.mainCanvas.centerObject(rect);
const circle = new fabric.Circle({
left: 80,
top: 50,
fill: 'pink',
radius: 50,
});
this.mainCanvas.add(circle);
this.mainCanvas.centerObject(circle);
const sequre = new fabric.Rect({
left: 300,
top: 350,
fill: 'blue',
width: 100,
height: 100,
});
this.mainCanvas.add(sequre);
const textbox = new fabric.Textbox('ABC Text', {
left: 300,
top: 100,
width: 150,
fontSize: 25,
textAlign: 'center',
});
this.mainCanvas.add(textbox);
this.mainCanvas.on('touch:gesture', (e) => {
console.log('touch:gesture', e);
});
this.mainCanvas.on('touch:drag', (e) => {
console.log('touch:drag', e);
});
this.mainCanvas.on('mouse:wheel', (opt) => {
var delta = opt.e.deltaY;
var zoom = this.mainCanvas.getZoom();
zoom *= 0.999 ** delta;
if (zoom > 20) zoom = 20;
if (zoom < 0.01) zoom = 0.01;
this.mainCanvas.zoomToPoint({ x: opt.e.offsetX, y: opt.e.offsetY }, zoom);
opt.e.preventDefault();
opt.e.stopPropagation();
var vpt = this.mainCanvas.viewportTransform ?? [];
if (zoom < 400 / 1000) {
vpt[4] = 200 - (1000 * zoom) / 2;
vpt[5] = 200 - (1000 * zoom) / 2;
} else {
if (vpt[4] >= 0) {
vpt[4] = 0;
} else if (vpt[4] < this.mainCanvas.getWidth() - 1000 * zoom) {
vpt[4] = this.mainCanvas.getWidth() - 1000 * zoom;
}
if (vpt[5] >= 0) {
vpt[5] = 0;
} else if (vpt[5] < this.mainCanvas.getHeight() - 1000 * zoom) {
vpt[5] = this.mainCanvas.getHeight() - 1000 * zoom;
}
}
});
this.mainCanvas.on('mouse:down', (opt) => {
var evt = opt.e;
if (evt.altKey === true) {
this.isDragging = true;
this.selection = false;
this.lastPosX = evt.clientX;
this.lastPosY = evt.clientY;
}
});
this.mainCanvas.on('mouse:move', (opt) => {
if (this.isDragging) {
var e = opt.e;
var vpt = this.mainCanvas.viewportTransform ?? [];
vpt[4] += e.clientX - this.lastPosX;
vpt[5] += e.clientY - this.lastPosY;
this.mainCanvas.requestRenderAll();
this.lastPosX = e.clientX;
this.lastPosY = e.clientY;
}
});
this.mainCanvas.on('mouse:up', (opt) => {
// on mouse up we want to recalculate new interaction
// for all objects, so we call setViewportTransform
this.mainCanvas.setViewportTransform(
this.mainCanvas.viewportTransform ?? []
);
this.isDragging = false;
this.selection = true;
});
}
}
<p>Start editing to see some magic happen :)</p>
<p>
angular <b>v{{ version }}</b>
</p>
<div style="border: 1px solid">
<canvas #mainHtmlCanvas></canvas>
</div>
“fabric”: “5.3.0”,
“@types/fabric”: “^5.3.4”,
“typescript”: “4.8.2”,
“angular”: “14.2.0”