网格画法:react-konva 画网格,可拖动、可放大缩小、并带有坐标系 0 0 位置辅助线

发布于:2023-01-11 ⋅ 阅读:(269) ⋅ 点赞:(0)

React-konva 画网格

网格:一种可以在 canvas 面板上绘制图形的辅助线集合。

在这里插入图片描述
我们设定 canvas 初始化左上角顶点为 0,0 点,向右👉和向下👇是 X Y 轴正方向

一、React-konva

1、konva 介绍

Konva 中文网
React-konva

2、react-konva 示例

import { Stage, Layer, Rect, Circle } from 'react-konva';

export const App = () => {
  return (
    // Stage - is a div wrapper
    // Layer - is an actual 2d canvas element, so you can have several layers inside the stage
    // Rect and Circle are not DOM elements. They are 2d shapes on canvas
    <Stage width={window.innerWidth} height={window.innerHeight}>
      <Layer>
        <Rect width={50} height={50} fill="red" />
        <Circle x={200} y={200} stroke="black" radius={50} />
      </Layer>
    </Stage>
  );
}

3、代码

1. konva-canvas.tsx

import React, { useState } from "react";
import { Button } from 'antd';
import { Stage } from "react-konva";
import { LineGrid } from '../components/line-grid';

export const KonvasCanvas = () => {
    const [scale, setScale] = useState<number>(1); // 缩放比例
    const [stagePos, setStagePos] = React.useState({ x: 0, y: 0 }); // 页面 0 0 坐标位置
    const [CanvasWidth] = useState<number>(600); // canvas 宽度
    const [CanvasHeight] = useState<number>(400); // canvas 高度
    
    /**
     * 点击缩放
     */
    const clickScale = () => {
        const scaleVal = scale + 1 > 6 ? 1 : scale + 1;
        setScale(scaleVal);
    }
    return (
        <div className='konva' style={{ width: '600px', margin: '20px auto', }}>
            <Button onClick={clickScale}>缩放{scale}</Button>
            <div id="konva-canvas">
                <Stage
                    x={stagePos.x}
                    y={stagePos.y}
                    width={CanvasWidth}
                    height={CanvasHeight}
                    strokeWidth={1}
                    draggable
                    onDragMove={e => {
                    	// 拖动事件,设置 stagePos 值
                        const { x, y } = e.currentTarget.position();
                        setStagePos({
                            x: Math.round(x),
                            y: Math.round(y),
                        });
                    }}
                >
                    <LineGrid scale={scale} CanvasWidth={CanvasWidth} CanvasHeight={CanvasHeight} stagePos={stagePos} />
                </Stage>
            </div>
        </div>
    )
};

2. LineGrid.tsx

import React, { useState } from 'react';
import { Layer, Rect, Line } from "react-konva";

export const LineGrid = (props: any) => {
    const { scale, stagePos, CanvasWidth, CanvasHeight } = props;
    // 需要插入的网格 components
    const gridComponents = [];
    // 网格分成多少份 宽度 * 倍数 / 需要多少网格数
    const girdSize = 100 * scale / 20;
    // canvas X、Y 轴距离 stagePos x y 的距离
    const canvasXHeight = CanvasHeight - stagePos.y;
    const canvasYWidth = CanvasWidth - stagePos.x;
    const [solidColor] = useState<string>('#CCCCCC70'); // 实线颜色
    const [dashedColor] = useState<string>('#CCCCCC25'); // 虚线颜色
    const [zeroColor] = useState<string>('#358bf3'); // 0 点颜色
    const [strokeWidth] = useState<number>(1); // strokeWidth
    const [shadowOpacity] = useState<number>(0); // shadowOpacity
    const [shadowEnabled] = useState<boolean>(false); // shadowEnabled

    // 从 pageSlicePos.y 处开始往 Y 轴正方向画 X 轴网格
    const xPageSliceTotal = Math.ceil(canvasXHeight / girdSize);
    for (let i = 0; i < xPageSliceTotal; i++) {
        gridComponents.push(<Line
            x={0 - stagePos.x}
            y={girdSize * i}
            strokeWidth={strokeWidth}
            shadowOpacity={shadowOpacity}
            shadowEnabled={shadowEnabled}
            points={[0, 0, CanvasWidth, 0]}
            stroke={i === 0 ? zeroColor : i % 5 === 0 ? solidColor : dashedColor}
        />)
    }

    // 从 pageSlicePos.y 处开始往 Y 轴负方向画 X 轴网格
    const xRemaining = stagePos.y;
    const xRemainingTotal = Math.ceil(xRemaining / girdSize);
    for (let i = 0; i < xRemainingTotal; i++) {
        if (i === 0) continue;
        gridComponents.push(<Line
            x={0 - stagePos.x}
            y={-girdSize * i}
            strokeWidth={strokeWidth}
            shadowOpacity={shadowOpacity}
            shadowEnabled={shadowEnabled}
            points={[0, 0, CanvasWidth, 0]}
            stroke={i === 0 ? zeroColor : i % 5 === 0 ? solidColor : dashedColor}
        />)
    }

    // 从 pageSlicePos.x 处开始往 X 轴正方向画 Y 轴网格
    const yPageSliceTotal = Math.ceil(canvasYWidth / girdSize); // 计算需要绘画y轴的条数
    for (let j = 0; j < yPageSliceTotal; j++) {
        gridComponents.push(<Line
            x={girdSize * j}
            y={0 - stagePos.y}
            strokeWidth={strokeWidth}
            shadowOpacity={shadowOpacity}
            shadowEnabled={shadowEnabled}
            points={[0, 0, 0, CanvasHeight]}
            stroke={j === 0 ? zeroColor : j % 5 === 0 ? solidColor : dashedColor}
        />)
    }

    // 从 pageSlicePos.x 处开始往 X 轴负方向画 Y 轴网格
    const yRemaining = stagePos.x;
    const yRemainingTotal = Math.ceil(yRemaining / girdSize);
    for (let j = 0; j < yRemainingTotal; j++) {
        if (j === 0) continue;
        gridComponents.push(<Line
            x={-girdSize * j}
            y={0 - stagePos.y}
            strokeWidth={strokeWidth}
            shadowOpacity={shadowOpacity}
            shadowEnabled={shadowEnabled}
            points={[0, 0, 0, CanvasHeight]}
            stroke={j === 0 ? zeroColor : j % 5 === 0 ? solidColor : dashedColor}
        />)
    }

    // 0 0 位置画一个 10 10 的红色 rect 矩形
    gridComponents.push(<Rect
        x={0}
        y={0}
        width={10}
        height={10}
        fill="red"
    />);

    return (
        <Layer>
            {gridComponents}
        </Layer>
    );
};

4、效果图

在这里插入图片描述

5、代码

github 链接
码云链接

本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到