使用平移系统在Vue Canvas中实现无限网格点

问题描述 投票:0回答:1

我目前正在努力在我的 Vue 应用程序中向画布添加平移系统。虽然我已经成功实现了平移系统,但我面临着高效渲染无限点网格的挑战。

这是我的组件的代码:

<template>
  <div>
    <div>
      <canvas
        @mousedown="baseEditorMouseDown"
        @mouseup="baseEditorMouseUp"
        @mousemove="baseEditorMouseMove"
        ref="baseEditor"
      ></canvas>
    </div>
  </div>
</template>
<script setup lang="ts">
import { ref, type Ref, computed, onMounted } from "vue";

const baseEditor: Ref<HTMLCanvasElement | null> = ref(null);

const context: Ref<CanvasRenderingContext2D | null> = ref(null);
const gridOffset = ref(50);
const imagePosition: Ref<any> = ref({
  x: 0,
  y: 0,
});

const canvasBaseImage = ref(new Image());
const isMasking = ref(false);
const lastMaskPosition: Ref<any> = ref({
  x: 0,
  y: 0,
});

const isPanning = ref(false);
const lastClickPosition = ref({ x: 0, y: 0 });
const lastOffsetTemp = ref({ x: 0, y: 0 });
const lastOffset = ref({ x: 0, y: 0 });

const computedGridCircles = computed(() => {
  var coords = [];
  for (
    let x = -window.innerWidth + gridOffset.value / 2;
    x < window.innerWidth * 2;
    x += gridOffset.value
  ) {
    for (
      let y = -window.innerHeight + gridOffset.value / 2;
      y < window.innerHeight * 2;
      y += gridOffset.value
    ) {
      coords.push({
        x,
        y,
      });
    }
  }

  return coords;
});

function drawGridCircles() {
  if (context.value) {
    context.value.beginPath();

    for (let i = 0; i < computedGridCircles.value.length; i++) {
      const coord = computedGridCircles.value[i];
      context.value.rect(
        coord.x + lastOffsetTemp.value.x + lastOffset.value.x,
        coord.y + lastOffsetTemp.value.y + lastOffset.value.y,
        3,
        3
      );
    }
    context.value.fillStyle = "#333";
    context.value.fill();
  }
}

function baseEditorMouseMove(event: MouseEvent) {
  if (isPanning.value) {
    lastOffset.value.x = event.clientX - lastClickPosition.value.x;
    lastOffset.value.y = event.clientY - lastClickPosition.value.y;
    updatePanning();
  }
}

function baseEditorMouseDown(event: MouseEvent) {
  isPanning.value = true;
  lastClickPosition.value.x = event.clientX;
  lastClickPosition.value.y = event.clientY;
}

function baseEditorMouseUp(event: MouseEvent) {
  isMasking.value = false;
  isPanning.value = false;

  lastOffsetTemp.value.x += lastOffset.value.x;
  lastOffsetTemp.value.y += lastOffset.value.y;
}

function clearCanvas() {
  if (context.value) {
    context.value.clearRect(0, 0, window.innerWidth, window.innerHeight);
  }
}
function updatePanning() {
  clearCanvas();
  drawGridCircles();
}

onMounted(() => {
  if (baseEditor.value) {
    context.value = baseEditor.value.getContext("2d");

    baseEditor.value.width = window.innerWidth;
    baseEditor.value.height = window.innerHeight;
  }

  drawGridCircles();
});
</script>

在compatedGridCircles函数中,我根据用户的窗口大小计算网格点的坐标。然而,这并没有提供无限的网格。我参考了一些资源,包括:

但是我在数学计算中遗漏了一些东西。

这里有一个 StackBlitz 演示,以便更好地理解。 https://stackblitz.com/edit/vue3-vite-typescript-starter-21gys6?file=src%2FApp.vue

我感谢任何有关通过高效渲染实现无限网格的指导。谢谢您的帮助!

vue.js html5-canvas
1个回答
0
投票

我相信我已经找到了解决方案。

首先,用户无法抓取超出其屏幕分辨率允许的内容。因此,我推断起始坐标和终止坐标之间的差异应该超过屏幕分辨率。

例如,我有一个 1920x1080 的显示器,因此开始和停止 X 位置之间的差异应大于 1920,才能呈现无限滚动的外观。为了确保这一点,我还添加了五倍网格大小的差值。同样的原理也适用于垂直位置。

我绘制与可见区域相当的矩形,以防止抓取太多后出现滞后或冻结问题。

这就是我修改我的

drawGridCircles
功能的方式:

function drawGridCircles() {
  if (context.value) {
    context.value.beginPath();

    const startX = Math.floor(-currentOffsetPositions.value.x / gridSize.value) * gridSize.value + gridSize.value / 2;
    const startY = Math.floor(-currentOffsetPositions.value.y / gridSize.value) * gridSize.value + gridSize.value / 2;

    const finishX = startX + window.innerWidth + gridSize.value * 5
    const finishY = startY + window.innerHeight + gridSize.value * 5

    for (let x = startX; x < finishX; x += gridSize.value) {
      for (let y = startY; y < finishY; y += gridSize.value) {
        context.value.rect(x + currentOffsetPositions.value.x, y + currentOffsetPositions.value.y, 3, 3)
      }
    }


    context.value.fillStyle = "#333";
    context.value.fill();
  }
}

完整代码可以在这里找到: https://stackblitz.com/edit/vue3-vite-typescript-starter-qf1cey?file=src%2FApp.vue

© www.soinside.com 2019 - 2024. All rights reserved.