简体   繁体   English

canvas Angular 中的放大和缩小图像问题

[英]Issue with zoom in and zoom out image in canvas Angular

I am having issues when I try to zoom in and out of a canvas image.当我尝试放大和缩小 canvas 图像时遇到问题。

The aim is to allow users to draw rectangles on the image.目的是允许用户在图像上绘制矩形。 I am using canvas to display the image and then draw rectangles on image, this is working fine.我正在使用 canvas 显示图像,然后在图像上绘制矩形,这工作正常。 But now I am trying to add zoom in and zoom out functionality.但现在我正在尝试添加放大和缩小功能。 I am facing following issue:我面临以下问题:

When I zoom in or zoom out, I need to keep the rectangles in same place with respect to the image.当我放大或缩小时,我需要将矩形保持在相对于图像的相同位置。 The rectangle stays in the same coordinate location, but as the image is moved, the part of image in the rectangle has changed.矩形保持在相同的坐标位置,但是随着图像的移动,矩形中的图像部分发生了变化。 How to keep the rectangle to cover same part of image even after zoom in/zoom out.即使在放大/缩小后如何保持矩形覆盖图像的同一部分。

I am new to canvas and not sure how to get this working.我是 canvas 的新手,不知道如何让它工作。

Here is the component that I am having trouble with:这是我遇到问题的组件:

tagger.component.html标记器.component.html

<div class="row">
  <div class="text-image-content">
 
    <div class="column1">
        <div style="position: relative;">
            <div *ngFor="let drawItem of drawItems; let i = index">
                <input [ngStyle]="{'left':drawItem.x0 + 'px' , 'top': drawItem.y0 + 'px'}"
                    style="position: absolute; z-index: 999;" placeholder="Enter Object Name"
                    [(ngModel)]="drawItem.name" type="text">
                <input [ngStyle]="{'left':drawItem.x0 + 'px' , 'top': drawItem.y0 + 'px'}"
                    style="position: absolute; z-index: 999;" type="button" value="X" (click)="delete(i)">
            </div>
            
            <canvas #layer1 id="layer1" style="position: absolute; left: 0; top: 0; z-index: 0;"></canvas>
            <div class="row">
            </div>
        </div>
    </div>
    </div>
<button class="zoomBtn" (click)="zoomIn()">Zoom in</button>
<button class="zoomBtn" (click)="zoomOut()">Zoom out</button>
    <div class="column2">
        <div *ngFor="let drawItem of originalItems; let i = index">
            <div class="details">
              <div >Name: {{drawItem.name | titlecase}} </div>
               <div>({{drawItem.x0}}, {{drawItem.y0}} , {{drawItem.x0 + drawItem.x1}}, {{drawItem.y0 + drawItem.y1}})</div>
            </div>
        </div>
    </div>
</div>

tagger.component.ts tagger.component.ts

import {
    Component,
    ViewChild,
    Input,
    Output,
    OnInit,
    EventEmitter,
    ElementRef
} from '@angular/core';

@Component({
    selector: "app-tagger",
    templateUrl: "./tagger.component.html",
    styleUrls: ["./tagger.component.scss"]
})
export class TaggerComponent implements OnInit {

    name = "Angular";
    constructor() { }
    drawItems = []
    originalItems = []
    count = 0
    @Input('CanvasHeight') CanvasHeight
    @Input('CanvasWidth') CanvasWidth
    @Output() selected = new EventEmitter();
    taggedItem = ""
    showInput: boolean = false;
    isMoving: boolean;
    public imgWidth: number;
    public uniX: number;
    public uniY: number;
    public uniX2: number;
    public uniY2: number;
    public initX: number;
    public initY: number;
    public imgHeight: number;
    public url: string;
    public image;
    public originalImageWidth;
    public originalImageHeight;
    public hRatio;
    public vRatio;
    public translatePos = {x: this.CanvasWidth / 2, y: this.CanvasHeight / 2};
    public scale = 1.0;
    public scaleMultiplier = 0.8;

    @ViewChild("layer1", { static: false }) layer1Canvas: ElementRef;
    private context: CanvasRenderingContext2D;
    private layer1CanvasElement: any;

  ngOnInit(){
    this.imageLoad();
  }

    delete(i) {
        console.log(i)
        this.drawItems.splice(i, 1);
        this.originalItems.splice(i,1);
        this.drawRect("red", 0, 0, 1);
    }

    imageLoad() {
      this.image = new Image();
      this.image.src = "https://i.ibb.co/12TJSNy/patio.jpg";
      this.image.onload = () => {
        console.log(this.CanvasWidth, this.CanvasHeight);
        console.log(this.image.width, this.image.height);
        this.originalImageWidth = this.image.width;
        this.originalImageHeight = this.image.height;
        this.image.width = this.CanvasWidth;
        this.image.height = this.CanvasHeight;
        this.hRatio =   this.originalImageWidth/this.CanvasWidth;
        this.vRatio =  this.originalImageHeight/this.CanvasHeight; 
        this.layer1CanvasElement = this.layer1Canvas.nativeElement;
        this.layer1CanvasElement.width = this.CanvasWidth;
        this.layer1CanvasElement.height = this.CanvasHeight;
        this.showImage();
      }
    }

    showImage() {
        this.count ++;
        this.layer1CanvasElement = this.layer1Canvas.nativeElement;
        this.context = this.layer1CanvasElement.getContext("2d");
        this.context.clearRect(0, 0, this.CanvasWidth, this.CanvasHeight);
        this.context.save();
        this.context.translate(this.translatePos.x, this.translatePos.y);
        this.context.scale(this.scale, this.scale);
        this.context.drawImage(this.image, 0,0, this.image.width, this.image.height);
        this.context.restore()
        let parent = this;
        if(this.count==1){
          this.layer1CanvasElement.addEventListener("mousedown", (e) => {
            this.isMoving = true
            this.initX = e.offsetX;
            this.initY = e.offsetY;
          });

        this.layer1CanvasElement.addEventListener("mouseup", (e) => {
            this.isMoving = false
            this.showInput = true
            this.drawItems.push({
                name: "",
                x0: this.initX,
                y0: this.initY,
                x1: this.uniX,
                y1: this.uniY
            });
            this.originalItems.push({
                name: "",
                x0: Math.ceil(this.initX * this.hRatio),
                y0: Math.ceil(this.initY * this.vRatio),
                x1: Math.ceil(this.uniX *this.hRatio),
                y1: Math.ceil(this.uniY * this.vRatio)
            });
            parent.drawRect("red", e.offsetX - this.initX, e.offsetY - this.initY, 0);
            this.uniX = undefined
            this.uniY = undefined
        });
      }
        

        this.layer1CanvasElement.addEventListener("mousemove", (e) => {
            if (this.isMoving) {
                parent.drawRect("red", e.offsetX - this.initX, e.offsetY - this.initY, 0);
            }
        });

        this.drawRect("red", 0, 0, 1);

    }


    drawRect(color = "black", height, width, flag) {
      if (this.uniX | flag) {
        this.context.clearRect(0, 0, this.CanvasWidth, this.CanvasHeight);
        this.context.save();
        this.context.translate(this.translatePos.x, this.translatePos.y);
        this.context.scale(this.scale, this.scale);
        this.context.drawImage(this.image, 0,0, this.image.width, this.image.height);
        this.context.restore()
      }
      // console.log(this.image.width, this.image.height)
      this.uniX = height
      this.uniY = width
      this.uniX2 = height
      this.uniY2 = width
      for (var i = 0; i < this.drawItems.length; i++) {
          this.context.beginPath();
          this.context.rect(
              this.drawItems[i].x0,
              this.drawItems[i].y0,
              this.drawItems[i].x1,
              this.drawItems[i].y1
          );
          this.context.lineWidth = 3;
          this.context.strokeStyle = color;
          this.context.stroke();
      }
    }

    zoomIn(){
      console.log("zooming in")
      this.scale /= this.scaleMultiplier;
      this.showImage();
    }
    zoomOut(){
      console.log("zooming out")
      this.scale *= this.scaleMultiplier;
      this.showImage();
      
    }
}

tagger.component.scsss tagger.component.scsss

.button {
    color: transparent;
    cursor: pointer;
}

.column1 {
    float: left;
    width: 70%;
    padding: 10px;
    height: 300px; /* Should be removed. Only for demonstration */
}
.column2 {
    float: left;
    width: 25%;
    padding: 10px;
    height: 300px; /* Should be removed. Only for demonstration */
}

/* Clear floats after the columns */
.row:after {
    content: "";
    display: table;
    clear: both;
}

.details {
    margin: 10px;
}

.text-image-content{
border: 1px solid #979797;
    border-radius: 8px;
    padding: 0 10px;
    margin-left:20px;
    margin-right:20px;
    height: 300px;
    overflow-y: scroll;
    overflow-x: scroll;
    scrollbar-width: thin;
}

.zoomBtn{
  // height:10px;
}

The complete code can be found in: https://stackblitz.com/edit/angular-tsotfa?file=src%2Fapp%2Ftagger%2Ftagger.component.ts完整代码见: https://stackblitz.com/edit/angular-tsotfa?file=src%2Fapp%2Ftagger%2Ftagger.component.ts

Thanks!谢谢!

In your Zoomin or Zoomout function, reduce or increase the value of the coordinates of the bounding boxes ie this.drawItems.在您的 Zoomin 或 Zoomout function 中,减少或增加边界框的坐标值,即 this.drawItems。 That will do your work.那会做你的工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM