放大/缩小后无法在画布上正确绘制(缩放)

时间:2020-07-07 03:57:42

标签: javascript html angular canvas html5-canvas

缩放后我无法正确绘制。

目的是允许用户在图像上绘制矩形。我正在使用画布显示图像,然后在图像上绘制矩形,效果很好。但是现在我正在尝试添加放大和缩小功能。放大/缩小后,我需要移动矩形,才能正确进行操作。

我有3个保存矩形坐标的数组:

  1. drawItems:绘制时的初始矩形坐标
  2. currentItems:缩放以显示矩形后的坐标
  3. originalItems:相对于原始图片尺寸(而不是画布)的坐标

当我缩放画布并出于某种原因尝试在特定位置绘制矩形时,

我是Canvas和Angular的新手,请让我知道我要去哪里了。

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 = []
    currentItems = []
    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.9;
   
   
    public previousScale = 1.0;

    @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 ++;
        var s = Math.max(this.CanvasWidth / this.image.width, this.CanvasHeight / this.image.height);
        console.log(s)
        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
            var a = this.initX * this.scale
            var b = this.initY * this.scale
            var c = this.uniX * this.scale
            var d = this.uniY * this.scale
            console.log(this.initX,this.initY,this.uniX,this.uniY)
            console.log(a,b,c,d)
            this.drawItems.push({
                name: "",
                x0: a,
                y0: b,
                x1: c,
                y1: d
            });
             this.currentItems.push({
                x0: a,
                y0: b,
                x1: c,
                y1: d
            });
            this.originalItems.push({
                name: "",
                x0: Math.ceil(a * this.hRatio),
                y0: Math.ceil(b * this.vRatio),
                x1: Math.ceil(c *this.hRatio),
                y1: Math.ceil(d * 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()
      }
      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.currentItems[i].x0,
              this.currentItems[i].y0 ,
              this.currentItems[i].x1 ,
              this.currentItems[i].y1 
          );
          this.context.lineWidth = 3;
          this.context.strokeStyle = color;
          this.context.stroke();
      }
    }
    scaleUpBoundingBox(){
      for (var i = 0; i < this.drawItems.length; i++) {
        this.currentItems[i].x0 = this.drawItems[i].x0 * this.scale;
        this.currentItems[i].y0 = this.drawItems[i].y0 * this.scale;
        this.currentItems[i].x1 = this.drawItems[i].x1 * this.scale;
        this.currentItems[i].y1 = this.drawItems[i].y1 * this.scale;
      }
    }

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

tagger-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 * scale + 'px' , 'top': drawItem.y0  *scale + '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.scss

.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;
}

完整的代码可以在这里找到:https://stackblitz.com/edit/angular-ckfmpv

0 个答案:

没有答案