I tried to draw an rectangle on canvas element using typescript(angular), but its not working as expected, at the same i created in javascript its working. Please look at the below code,
export class AppComponent {
@Input() width = 512;
@Input() height = 418;
@ViewChild('canvas') canvas: ElementRef;
cx: CanvasRenderingContext2D;
drawingSubscription: Subscription;
name = 'Angular ' VERSION.major;
ngAfterViewInit() {
const canvasEl: HTMLCanvasElement = this.canvas.nativeElement;
this.cx = canvasEl.getContext('2d');
canvasEl.width = this.width;
canvasEl.height = this.height;
this.cx.lineWidth = 2;
//this.cx.lineCap = 'round';
this.captureEvents(canvasEl);
}
captureEvents(canvasEl: HTMLCanvasElement) {
var startX;
var startY;
var mouseX;
var mouseY;
// this will capture all mousedown events from teh canvas element
this.drawingSubscription = fromEvent(canvasEl, 'mousedown')
.pipe(
switchMap((e) => {
// after a mouse down, we'll record all mouse moves
return fromEvent(canvasEl, 'mousemove').pipe(
// we'll stop (and unsubscribe) once the user releases the mouse
// this will trigger a 'mouseup' event
takeUntil(fromEvent(canvasEl, 'mouseup')),
// we'll also stop (and unsubscribe) once the mouse leaves the canvas (mouseleave event)
takeUntil(fromEvent(canvasEl, 'mouseleave')),
// pairwise lets us get the previous value to draw a line from
// the previous point to the current point
pairwise()
);
})
)
.subscribe((res: [MouseEvent, MouseEvent]) => {
const rect = canvasEl.getBoundingClientRect();
console.log(res[0]);
// previous and current position with the offset
startX = res[0].clientX - rect.left;
startY = res[0].clientY - rect.top;
console.log(startX, startY);
const prevPos = {
x: res[0].clientX - rect.left,
y: res[0].clientY - rect.top,
};
const currentPos = {
x: res[1].clientX - rect.left,
y: res[1].clientY - rect.top,
};
mouseX = res[0].clientX - rect.left;
mouseY = res[0].clientY - rect.top;
this.cx.clearRect(0, 0, canvasEl.width, canvasEl.height);
var width = mouseX - startX;
var height = mouseY - startY;
this.cx.strokeRect(startX, startY, width, height);
console.log(startX, startY, width, height);
});
}
ngOnDestroy() {
// this will remove event lister when this component is destroyed
this.drawingSubscription.unsubscribe();
}
}
Html code:
<canvas #canvas> </canvas>
Please check my live code on stackblitz : https://stackblitz.com/edit/angular-ivy-iqjbew?file=src/app/app.component.ts
And Working examples of Javascript : https://jsfiddle.net/sathishcst10/wp2anys7/12/
CodePudding user response:
The JS code and the TS code are not the same. You have an error in your TS code.
startX = res[0].clientX - rect.left;
startY = res[0].clientY - rect.top;
mouseX = res[0].clientX - rect.left;
mouseY = res[0].clientY - rect.top;
var width = mouseX - startX;
var height = mouseY - startY;
As you can see startX and mouseX are exactly the same, thus width and height will always be ZERO and the rect will not be visible.
Here a quick way to fix this, but probably there are better ways
this.drawingSubscription = fromEvent(canvasEl, 'mousedown')
.pipe(
tap((e) => {
startX = null;
startY = null;
}),
switchMap((e) => {
// your code
})
)
.subscribe((res: [MouseEvent, MouseEvent]) => {
const rect = canvasEl.getBoundingClientRect();
if (startX === null) {
startX = res[0].clientX - rect.left;
startY = res[0].clientY - rect.top;
}
// your code
CodePudding user response:
I suggest not use pairwise, you can use simply tap to store the position in mouseDown. Futhermore, I like more use a merge from events mouseup and mouseleave with take(1)
More or less:
captureEvents(canvasEl: HTMLCanvasElement) {
const rect = canvasEl.getBoundingClientRect();
const prevPos = {x:0,y:0};
// this will capture all mousedown events from teh canvas element
this.drawingSubscription = fromEvent(canvasEl, 'mousedown')
.pipe(
tap((e:MouseEvent)=>{
prevPos.x= e.clientX - rect.left
prevPos.y=e.clientY - rect.top
}),
switchMap((e) => {
// after a mouse down, we'll record all mouse moves
return fromEvent(canvasEl, 'mousemove').pipe(
// we'll stop (and unsubscribe) once the user releases the mouse
// this will trigger a 'mouseup' event
takeUntil(
merge(fromEvent(canvasEl, 'mouseup'),
fromEvent(canvasEl, 'mouseleave'))
.pipe(take(1))),
);
})
)
.subscribe((res:MouseEvent) => {
const currentPos = {
x: res.clientX - rect.left,
y: res.clientY - rect.top,
};
this.cx.clearRect(0, 0, canvasEl.width, canvasEl.height);
const width = currentPos.x-prevPos.x;
const height = currentPos.y-prevPos.y;
this.cx.strokeRect(prevPos.x, prevPos.y, width, height);
// this method we'll implement soon to do the actual drawing
// this.drawOnCanvas(prevPos, currentPos);
});
}
NOTE: In typescript not use "var" to declare a variable else or "let" or "const"