npm package: @scory02/grid-view
Description: 一个高性能的 Vue 无限生长网格视图组件，可用于可视化编辑器、画布等场景。
Author: scory02
Latest version: 1.0.1

# @scory02/grid-view

一个高性能的 Vue 无限生长网格视图组件，可用于可视化编辑器、画布等场景。

## 安装
```bash
npm install @scory02/grid-view
```

## 使用方法
```vue
<template>
  <GridView :gridType="'lines'" :zoomLevel="100" />
</template>

<script>
import GridView from '@scory02/grid-view/gridView.vue'
export default {
  components: { GridView }
}
</script>
```

## 完整使用代码
```vue
<template>
  <div>
    <div 
      class="grid-root" 
      @wheel="onWheel" 
      @mousedown="onMouseDown"
      @mousemove="onMouseMove"  
      @mouseup="onMouseUp"
      @mouseleave="onMouseLeave">
      <gridView v-bind="paneOptions" />
    </div>

    <div ref="paneContainer" class="pane-container"></div>
  </div>
</template>

<script>
import gridView from '@scory02/grid-view/gridView.vue';
import { Pane } from "tweakpane";

export default {
  components: { gridView },
  data() {
    return {
      paneOptions: {
        gridType: 'lines',
        zoomLevel: 100,
        gridSize: 100,
        max_size: 2,
        viewX: 0,
        viewY: 0,
        gridColor: '#000000'
      },
      isDragging: false,
      lastX: 0,
      lastY: 0,
      min_zoom: 1,
      max_zoom: 1000,
      pane: null
    };
  },
  mounted() {
    this.pane = new Pane({
      title: 'Grid Controls',
      container: this.$refs.paneContainer
    });
    this.pane.addBinding(this.paneOptions, 'gridType', {
      options: { '网格': 'lines', '点阵': 'dots' }
    });
    this.pane.addBinding(this.paneOptions, 'gridColor', { label: '颜色' });
    this.pane.addBinding(this.paneOptions, 'gridSize', {
      min: 50, max: 500, step: 1, label: '网格大小'
    });
    this.pane.addBinding(this.paneOptions, 'max_size', {
      min: 1, max: 10, step: 0.1, label: '点阵最大值'
    });
    this.pane.addBinding(this.paneOptions, 'zoomLevel', {
      min: this.min_zoom, max: this.max_zoom, step: 1, label: '缩放'
    }).on('input', ev => this.onZoomSliderPane(ev.value));
    this.pane.addBinding(this.paneOptions, 'viewX', {
      min: -1000, max: 1000, step: 1, label: 'X'
    });
    this.pane.addBinding(this.paneOptions, 'viewY', {
      min: -1000, max: 1000, step: 1, label: 'Y'
    });
  },
  methods: {
    onWheel(e) {
      e.preventDefault();
      const rect = e.currentTarget.getBoundingClientRect();
      const mouseX = e.clientX - rect.left;
      const mouseY = e.clientY - rect.top;
      const worldX = mouseX - this.paneOptions.viewX;
      const worldY = mouseY - this.paneOptions.viewY;
      const speed = Math.min(0.12, 0.06 + Math.log(this.paneOptions.zoomLevel + 1) * 0.015);
      const zoomFactor = e.deltaY > 0 ? 1 - speed : 1 + speed;
      const oldZoom = this.paneOptions.zoomLevel;
      this.paneOptions.zoomLevel = Math.min(this.max_zoom, Math.max(this.min_zoom, oldZoom * zoomFactor));
      const actualZoom = this.paneOptions.zoomLevel / oldZoom;
      this.paneOptions.viewX = mouseX - worldX * actualZoom;
      this.paneOptions.viewY = mouseY - worldY * actualZoom;
      this.pane.refresh();
    },
    onMouseDown(e) {
      this.isDragging = true;
      this.lastX = e.clientX;
      this.lastY = e.clientY;
    },
    onMouseMove(e) {
      if (!this.isDragging) return;
      this.paneOptions.viewX += e.clientX - this.lastX;
      this.paneOptions.viewY += e.clientY - this.lastY;
      this.lastX = e.clientX;
      this.lastY = e.clientY;
      this.pane.refresh();
    },
    onMouseUp() { this.isDragging = false; },
    onMouseLeave() { this.isDragging = false; },
    onZoomSliderPane(newZoom) {
      this.paneOptions.zoomLevel = Math.min(this.max_zoom, Math.max(this.min_zoom, newZoom));
    }
  }
}
</script>

<style scoped>
.grid-root {
  width: 100vw;
  height: 100vh;
  position: relative;
  overflow: hidden;
  background-color: rgb(225, 224, 224);
  user-select: none;
  touch-action: none;
  font-family: cursive;
}

.pane-container {
  position: absolute;
  top: 10px;
  right: 10px;
  z-index: 100;
}
</style>
```

## 属性说明
- gridType: 网格类型（lines/dots）
- gridColor: 网格颜色
- gridSize: 网格基础大小
- max_size: 线宽/点大小最大值
- zoomLevel: 缩放等级
- viewX/viewY: 视图偏移