You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular中使用KonvaJS实现轴图层缩放时固定显示的方法

解决KonvaJS轴图层不受舞台缩放影响的问题

要让轴图层在舞台缩放时保持视觉一致,核心是反向缩放轴图层抵消舞台的缩放比例,同时调整图层位置避免偏移,以下是具体实现步骤:

  • 监听舞台的transform事件(包含缩放、平移操作),实时同步轴图层的缩放与位置
  • 将轴图层的缩放值设为舞台缩放的倒数,抵消舞台缩放对轴线笔触和尺寸的影响
  • 调整轴图层的位置,补偿舞台平移带来的偏移

Angular场景下的代码实现

import { Component, OnInit, ViewChild, ElementRef } from '@angular/core';
import * as Konva from 'konva';

@Component({
  selector: 'app-canvas',
  template: '<div #container class="canvas-container"></div>'
})
export class CanvasComponent implements OnInit {
  @ViewChild('container') containerRef!: ElementRef;
  private stage!: Konva.Stage;
  private axisLayer!: Konva.Layer;
  private graphLayers: Konva.Layer[] = [];

  ngOnInit(): void {
    this.initStage();
    this.createLayers();
    this.renderAxes();
    this.bindStageTransformListener();
  }

  private initStage(): void {
    this.stage = new Konva.Stage({
      container: this.containerRef.nativeElement,
      width: 800,
      height: 600,
      draggable: true
    });
    // 鼠标滚轮缩放逻辑
    this.stage.on('wheel', (e) => {
      e.evt.preventDefault();
      const scaleBy = 1.1;
      const pointer = this.stage.getPointerPosition();
      const mouseX = pointer!.x - this.stage.x();
      const mouseY = pointer!.y - this.stage.y();
      const newScaleX = e.evt.deltaY > 0 ? this.stage.scaleX() / scaleBy : this.stage.scaleX() * scaleBy;
      const newScaleY = e.evt.deltaY > 0 ? this.stage.scaleY() / scaleBy : this.stage.scaleY() * scaleBy;

      this.stage.scale({ x: newScaleX, y: newScaleY });
      const newX = pointer!.x - mouseX * newScaleX;
      const newY = pointer!.y - mouseY * newScaleY;
      this.stage.position({ x: newX, y: newY });
      this.stage.batchDraw();
    });
  }

  private createLayers(): void {
    this.axisLayer = new Konva.Layer();
    this.graphLayers.push(new Konva.Layer(), new Konva.Layer());
    
    // 轴图层放在最底层,避免被图形遮挡
    this.stage.add(this.axisLayer, ...this.graphLayers);
  }

  private renderAxes(): void {
    const xAxis = new Konva.Line({
      points: [50, 550, 750, 550],
      stroke: '#2c3e50',
      strokeWidth: 2,
      lineCap: 'round'
    });

    const yAxis = new Konva.Line({
      points: [50, 50, 50, 550],
      stroke: '#2c3e50',
      strokeWidth: 2,
      lineCap: 'round'
    });

    this.axisLayer.add(xAxis, yAxis);
    this.axisLayer.draw();
  }

  private bindStageTransformListener(): void {
    this.stage.on('transform', () => {
      const stageScaleX = this.stage.scaleX();
      const stageScaleY = this.stage.scaleY();
      const stagePosX = this.stage.x();
      const stagePosY = this.stage.y();

      // 反向缩放轴图层,抵消舞台缩放效果
      this.axisLayer.scale({
        x: 1 / stageScaleX,
        y: 1 / stageScaleY
      });

      // 调整轴图层位置,补偿舞台平移带来的偏移
      this.axisLayer.position({
        x: stagePosX * (1 - 1 / stageScaleX),
        y: stagePosY * (1 - 1 / stageScaleY)
      });

      this.axisLayer.draw();
    });
  }
}

关键说明

  • 轴图层的缩放值设为舞台缩放的倒数,这样舞台放大多少倍,轴图层就缩小多少倍,视觉上保持原始尺寸
  • 位置调整公式是为了让轴的原点始终对齐舞台平移后的可视区域原点,避免轴线偏移
  • 如果只使用等比缩放(scaleX = scaleY),可以简化缩放和位置的计算逻辑
  • 轴图层建议放在所有图形图层的下方,避免被图形遮挡

内容的提问来源于stack exchange,提问作者Vikram Jain

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 20:22:30