From 061039c1ca31340eee86d432749a19b45651f167 Mon Sep 17 00:00:00 2001 From: zhangjiming Date: Wed, 5 Mar 2025 11:43:48 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=B1=82=E7=BB=84?= =?UTF-8?q?=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/measure/components/MeasureAction.tsx | 10 ++- src/pages/measure/components/SectionalView.tsx | 72 ---------------------- src/pages/measure/components/graph/AreaLayer.tsx | 31 ++++++++++ src/pages/measure/components/graph/GridLayer.tsx | 71 +++++++++++++++++++++ src/pages/measure/components/graph/MarkLayer.tsx | 31 ++++++++++ .../measure/components/graph/RealtimeLayer.tsx | 31 ++++++++++ .../measure/components/graph/StandardLayer.tsx | 31 ++++++++++ 7 files changed, 202 insertions(+), 75 deletions(-) delete mode 100644 src/pages/measure/components/SectionalView.tsx create mode 100644 src/pages/measure/components/graph/AreaLayer.tsx create mode 100644 src/pages/measure/components/graph/GridLayer.tsx create mode 100644 src/pages/measure/components/graph/MarkLayer.tsx create mode 100644 src/pages/measure/components/graph/RealtimeLayer.tsx create mode 100644 src/pages/measure/components/graph/StandardLayer.tsx diff --git a/src/pages/measure/components/MeasureAction.tsx b/src/pages/measure/components/MeasureAction.tsx index 750ad2b..bd09e85 100644 --- a/src/pages/measure/components/MeasureAction.tsx +++ b/src/pages/measure/components/MeasureAction.tsx @@ -1,7 +1,8 @@ import { Button, Checkbox, CheckboxProps, Radio, RadioChangeEvent } from "antd"; import { useState } from "react"; import { useNavigate } from "react-router"; -import SectionalView from "./SectionalView"; +import GridLayer from "./graph/GridLayer"; +import StandardLayer from "./graph/StandardLayer"; export default function MeasureAction() { const navigate = useNavigate(); @@ -18,8 +19,11 @@ export default function MeasureAction() { }; return (
-
- +
+ +
+ +

测量步骤

diff --git a/src/pages/measure/components/SectionalView.tsx b/src/pages/measure/components/SectionalView.tsx deleted file mode 100644 index eb03704..0000000 --- a/src/pages/measure/components/SectionalView.tsx +++ /dev/null @@ -1,72 +0,0 @@ -import { useCallback, useEffect, useRef } from "react"; - -const primaryLineColor = "rgb(203,213,245)"; -const subLineColor = "rgb(226,231,232)"; - -export default function SectionalView(props: { - width: number; - height: number; - leftPadding: number; - rightPadding: number; - topPadding: number; - bottomPadding: number; - columns: number; - rows: number; - cellNum: number; -}) { - const xStartPx = props.leftPadding; - const xEndPx = props.width - props.rightPadding; - const xStepPx = (props.width - props.leftPadding - props.rightPadding) / props.columns; - const xUnitPx = xStepPx / props.cellNum; - const yStartPx = props.topPadding; - const yEndPx = props.height - props.bottomPadding; - const yStepPx = (props.height - props.topPadding - props.bottomPadding) / props.rows; - const yUnitPx = yStepPx / props.cellNum; - - const canvasRef = useRef(null); - const drawGrid = useCallback((ctx: CanvasRenderingContext2D) => { - ctx.beginPath(); - ctx.strokeStyle = subLineColor; - for (let i = 1; i < props.columns * props.cellNum; ++i) { - if (i % props.cellNum === 0) continue; - ctx.moveTo(xStartPx + xUnitPx * i, yStartPx); - ctx.lineTo(xStartPx + xUnitPx * i, yEndPx); - } - for (let j = 1; j < props.rows * props.cellNum; ++j) { - if (j % props.cellNum === 0) continue; - ctx.moveTo(xStartPx, yStartPx + yUnitPx * j); - ctx.lineTo(xEndPx, yStartPx + yUnitPx * j); - } - ctx.stroke(); - - ctx.beginPath(); - ctx.strokeStyle = primaryLineColor; - for (let i = 0; i <= props.columns; ++i) { - ctx.moveTo(xStartPx + xStepPx * i, yStartPx); - ctx.lineTo(xStartPx + xStepPx * i, yEndPx); - } - for (let j = 0; j <= props.rows; ++j) { - ctx.moveTo(xStartPx, yStartPx + yStepPx * j); - ctx.lineTo(xEndPx, yStartPx + yStepPx * j); - } - ctx.stroke(); - },[props.cellNum, props.columns, props.rows, xEndPx, xStartPx, xStepPx, xUnitPx, yEndPx, yStartPx, yStepPx, yUnitPx]) - - useEffect(() => { - // 获取canvas的2D绘图上下文 - const canvas = canvasRef.current; - if (!canvas) return; - - const context = canvas.getContext("2d"); - if (!context) return; - // 使用context对象进行绘图 - drawGrid(context); - }, [drawGrid]); - - - return ( -
- -
- ); -} diff --git a/src/pages/measure/components/graph/AreaLayer.tsx b/src/pages/measure/components/graph/AreaLayer.tsx new file mode 100644 index 0000000..f7bcede --- /dev/null +++ b/src/pages/measure/components/graph/AreaLayer.tsx @@ -0,0 +1,31 @@ +import { useCallback, useEffect, useRef } from "react"; + +export default function AreaLayer(props: { + width: number; + height: number; + leftPadding: number; + rightPadding: number; + topPadding: number; + bottomPadding: number; +}) { + const canvasRef = useRef(null); + const draw = useCallback((ctx: CanvasRenderingContext2D) => { + // 使用context对象进行绘图 + ctx.fillStyle = "skyblue"; // 设置填充颜色 + ctx.fillRect(50, 50, 150, 100); // 绘制一个矩形 + }, []); + useEffect(() => { + const canvas = canvasRef.current; + if (!canvas) return; + + const context = canvas.getContext("2d"); + if (!context) return; + draw(context); + }, [draw]); + + return ( +
+ +
+ ); +} diff --git a/src/pages/measure/components/graph/GridLayer.tsx b/src/pages/measure/components/graph/GridLayer.tsx new file mode 100644 index 0000000..ed242e0 --- /dev/null +++ b/src/pages/measure/components/graph/GridLayer.tsx @@ -0,0 +1,71 @@ +import { useCallback, useEffect, useRef } from "react"; + +const primaryLineColor = "rgb(203,213,245)"; +const subLineColor = "rgb(226,231,232)"; + +export default function GridLayer(props: { + width: number; + height: number; + leftPadding: number; + rightPadding: number; + topPadding: number; + bottomPadding: number; + columns: number; + rows: number; + cellNum: number; +}) { + const xStartPx = props.leftPadding; + const xEndPx = props.width - props.rightPadding; + const xStepPx = (props.width - props.leftPadding - props.rightPadding) / props.columns; + const xUnitPx = xStepPx / props.cellNum; + const yStartPx = props.topPadding; + const yEndPx = props.height - props.bottomPadding; + const yStepPx = (props.height - props.topPadding - props.bottomPadding) / props.rows; + const yUnitPx = yStepPx / props.cellNum; + + const canvasRef = useRef(null); + const drawGrid = useCallback((ctx: CanvasRenderingContext2D) => { + ctx.beginPath(); + ctx.strokeStyle = subLineColor; + for (let i = 1; i < props.columns * props.cellNum; ++i) { + if (i % props.cellNum === 0) continue; + ctx.moveTo(xStartPx + xUnitPx * i, yStartPx); + ctx.lineTo(xStartPx + xUnitPx * i, yEndPx); + } + for (let j = 1; j < props.rows * props.cellNum; ++j) { + if (j % props.cellNum === 0) continue; + ctx.moveTo(xStartPx, yStartPx + yUnitPx * j); + ctx.lineTo(xEndPx, yStartPx + yUnitPx * j); + } + ctx.stroke(); + + ctx.beginPath(); + ctx.strokeStyle = primaryLineColor; + for (let i = 0; i <= props.columns; ++i) { + ctx.moveTo(xStartPx + xStepPx * i, yStartPx); + ctx.lineTo(xStartPx + xStepPx * i, yEndPx); + } + for (let j = 0; j <= props.rows; ++j) { + ctx.moveTo(xStartPx, yStartPx + yStepPx * j); + ctx.lineTo(xEndPx, yStartPx + yStepPx * j); + } + ctx.stroke(); + },[props.cellNum, props.columns, props.rows, xEndPx, xStartPx, xStepPx, xUnitPx, yEndPx, yStartPx, yStepPx, yUnitPx]) + + useEffect(() => { + // 获取canvas的2D绘图上下文 + const canvas = canvasRef.current; + if (!canvas) return; + + const context = canvas.getContext("2d"); + if (!context) return; + // 使用context对象进行绘图 + drawGrid(context); + }, [drawGrid]); + + return ( +
+ +
+ ); +} diff --git a/src/pages/measure/components/graph/MarkLayer.tsx b/src/pages/measure/components/graph/MarkLayer.tsx new file mode 100644 index 0000000..28bb3d8 --- /dev/null +++ b/src/pages/measure/components/graph/MarkLayer.tsx @@ -0,0 +1,31 @@ +import { useCallback, useEffect, useRef } from "react"; + +export default function MarkLayer(props: { + width: number; + height: number; + leftPadding: number; + rightPadding: number; + topPadding: number; + bottomPadding: number; +}) { + const canvasRef = useRef(null); + const draw = useCallback((ctx: CanvasRenderingContext2D) => { + // 使用context对象进行绘图 + ctx.fillStyle = "skyblue"; // 设置填充颜色 + ctx.fillRect(50, 50, 150, 100); // 绘制一个矩形 + }, []); + useEffect(() => { + const canvas = canvasRef.current; + if (!canvas) return; + + const context = canvas.getContext("2d"); + if (!context) return; + draw(context); + }, [draw]); + + return ( +
+ +
+ ); +} diff --git a/src/pages/measure/components/graph/RealtimeLayer.tsx b/src/pages/measure/components/graph/RealtimeLayer.tsx new file mode 100644 index 0000000..4d4c794 --- /dev/null +++ b/src/pages/measure/components/graph/RealtimeLayer.tsx @@ -0,0 +1,31 @@ +import { useCallback, useEffect, useRef } from "react"; + +export default function RealtimeLayer(props: { + width: number; + height: number; + leftPadding: number; + rightPadding: number; + topPadding: number; + bottomPadding: number; +}) { + const canvasRef = useRef(null); + const draw = useCallback((ctx: CanvasRenderingContext2D) => { + // 使用context对象进行绘图 + ctx.fillStyle = "skyblue"; // 设置填充颜色 + ctx.fillRect(50, 50, 150, 100); // 绘制一个矩形 + }, []); + useEffect(() => { + const canvas = canvasRef.current; + if (!canvas) return; + + const context = canvas.getContext("2d"); + if (!context) return; + draw(context); + }, [draw]); + + return ( +
+ +
+ ); +} diff --git a/src/pages/measure/components/graph/StandardLayer.tsx b/src/pages/measure/components/graph/StandardLayer.tsx new file mode 100644 index 0000000..f2bffeb --- /dev/null +++ b/src/pages/measure/components/graph/StandardLayer.tsx @@ -0,0 +1,31 @@ +import { useCallback, useEffect, useRef } from "react"; + +export default function StandardLayer(props: { + width: number; + height: number; + leftPadding: number; + rightPadding: number; + topPadding: number; + bottomPadding: number; +}) { + const canvasRef = useRef(null); + const draw = useCallback((ctx: CanvasRenderingContext2D) => { + // 使用context对象进行绘图 + ctx.fillStyle = "skyblue"; // 设置填充颜色 + ctx.fillRect(50, 50, 150, 100); // 绘制一个矩形 + }, []); + useEffect(() => { + const canvas = canvasRef.current; + if (!canvas) return; + + const context = canvas.getContext("2d"); + if (!context) return; + draw(context); + }, [draw]); + + return ( +
+ +
+ ); +} From 40ea0a7efa3f9a1b241bd3000a375a124d1e5d36 Mon Sep 17 00:00:00 2001 From: zhangjiming Date: Wed, 5 Mar 2025 17:02:01 +0800 Subject: [PATCH 2/3] =?UTF-8?q?=E7=BB=98=E5=88=B6=E6=A0=87=E5=87=86?= =?UTF-8?q?=E7=BA=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../measure/components/graph/StandardLayer.tsx | 119 ++++++++++++++++++++- src/utils/index.ts | 60 +++++++++++ 2 files changed, 177 insertions(+), 2 deletions(-) diff --git a/src/pages/measure/components/graph/StandardLayer.tsx b/src/pages/measure/components/graph/StandardLayer.tsx index f2bffeb..fde7c9f 100644 --- a/src/pages/measure/components/graph/StandardLayer.tsx +++ b/src/pages/measure/components/graph/StandardLayer.tsx @@ -1,4 +1,28 @@ import { useCallback, useEffect, useRef } from "react"; +import { calculateCircleAbove, calculateCircleBelow } from "../../../../utils"; + +const unitPx = 8; + +const pointsR: [number, number][] = [ + [0, 0], + [9.949007022412, 0.1650166186941], + [25.35, 2.184814802617], + [35.4, 14.20034968551], + [36.31679456414, 32.538841443], + [32.90417417089, 37.53190928715], + [20.0, 41.8333134842], +]; +const pointsL: [number, number][] = [ + [-20.0, 41.83331348425], + [-32.90417417089, 37.53190928715], + [-36.31679456414, 32.538841443], + [-35.4, 14.20034968551], + [-25.35, 2.184814802617], + [-9.949007022412, 0.1650166186941], + [0, 0], +]; +const pointsRight = pointsR.map(p => [p[0] * unitPx, p[1] * unitPx]); +const pointsLeft = pointsL.map(p => [p[0] * unitPx, p[1] * unitPx]); export default function StandardLayer(props: { width: number; @@ -9,10 +33,101 @@ export default function StandardLayer(props: { bottomPadding: number; }) { const canvasRef = useRef(null); + const draw = useCallback((ctx: CanvasRenderingContext2D) => { // 使用context对象进行绘图 - ctx.fillStyle = "skyblue"; // 设置填充颜色 - ctx.fillRect(50, 50, 150, 100); // 绘制一个矩形 + ctx.fillStyle = "blue"; + ctx.strokeStyle = "blue"; + + ctx.translate(400, 100); + ctx.moveTo(-400, 0); + ctx.lineTo(400, 0); + ctx.moveTo(0, -100); + ctx.lineTo(0, 500); + ctx.stroke(); + + ctx.beginPath(); + ctx.strokeStyle = "red"; + // ---- 右侧 + let point0 = pointsRight[0]; + let point1 = pointsRight[1]; + ctx.moveTo(point0[0], point0[1]); + let param = calculateCircleBelow(point0[0], point0[1], point1[0], point1[1], 300 * unitPx); + console.log(param); + ctx.arc(param.center.x, param.center.y, 300 * unitPx, param.anglesForCenter.startAngle, param.anglesForCenter.endAngle); + + point0 = pointsRight[1]; + point1 = pointsRight[2]; + ctx.moveTo(point0[0], point0[1]); + param = calculateCircleBelow(point0[0], point0[1], point1[0], point1[1], 80 * unitPx); + console.log(param); + ctx.arc(param.center.x, param.center.y, 80 * unitPx, param.anglesForCenter.startAngle, param.anglesForCenter.endAngle); + + point0 = pointsRight[2]; + point1 = pointsRight[3]; + ctx.moveTo(point0[0], point0[1]); + param = calculateCircleBelow(point0[0], point0[1], point1[0], point1[1], 13 * unitPx); + console.log(param); + ctx.arc(param.center.x, param.center.y, 13 * unitPx, param.anglesForCenter.startAngle, param.anglesForCenter.endAngle); + + point0 = pointsRight[3]; + point1 = pointsRight[4]; + ctx.moveTo(point0[0], point0[1]); + ctx.lineTo(point1[0], point1[1]); + + point0 = pointsRight[4]; + point1 = pointsRight[5]; + ctx.moveTo(point0[0], point0[1]); + param = calculateCircleAbove(point0[0], point0[1], point1[0], point1[1], 5 * unitPx); + console.log(param); + ctx.arc(param.center.x, param.center.y, 5 * unitPx, param.anglesForCenter.startAngle, param.anglesForCenter.endAngle); + + point0 = pointsRight[5]; + point1 = pointsRight[6]; + ctx.moveTo(point0[0], point0[1]); + ctx.lineTo(point1[0], point1[1]); + + // ---- 左侧 + point0 = pointsLeft[0]; + point1 = pointsLeft[1]; + ctx.moveTo(point0[0], point0[1]); + ctx.lineTo(point1[0], point1[1]); + + point0 = pointsLeft[1]; + point1 = pointsLeft[2]; + ctx.moveTo(point0[0], point0[1]); + param = calculateCircleAbove(point0[0], point0[1], point1[0], point1[1], 5 * unitPx); + console.log(param); + ctx.arc(param.center.x, param.center.y, 5 * unitPx, param.anglesForCenter.startAngle, param.anglesForCenter.endAngle); + + point0 = pointsLeft[2]; + point1 = pointsLeft[3]; + ctx.moveTo(point0[0], point0[1]); + ctx.lineTo(point1[0], point1[1]); + + point0 = pointsLeft[3]; + point1 = pointsLeft[4]; + ctx.moveTo(point0[0], point0[1]); + param = calculateCircleBelow(point0[0], point0[1], point1[0], point1[1], 13 * unitPx); + console.log(param); + ctx.arc(param.center.x, param.center.y, 13 * unitPx, param.anglesForCenter.startAngle, param.anglesForCenter.endAngle); + + point0 = pointsLeft[4]; + point1 = pointsLeft[5]; + ctx.moveTo(point0[0], point0[1]); + param = calculateCircleBelow(point0[0], point0[1], point1[0], point1[1], 80 * unitPx); + console.log(param); + ctx.arc(param.center.x, param.center.y, 80 * unitPx, param.anglesForCenter.startAngle, param.anglesForCenter.endAngle); + + point0 = pointsLeft[5]; + point1 = pointsLeft[6]; + ctx.moveTo(point0[0], point0[1]); + param = calculateCircleBelow(point0[0], point0[1], point1[0], point1[1], 300 * unitPx); + console.log(param); + ctx.arc(param.center.x, param.center.y, 300 * unitPx, param.anglesForCenter.startAngle, param.anglesForCenter.endAngle); + + ctx.stroke(); + // ctx.fillRect(100, 100, 150, 100); // 绘制一个矩形 }, []); useEffect(() => { const canvas = canvasRef.current; diff --git a/src/utils/index.ts b/src/utils/index.ts index 1c1eb9a..6c3a9b8 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -3,3 +3,63 @@ export function formatRemainTime(seconds: number) { const sec = (seconds % 60).toFixed(); return min.padStart(2, "0") + ":" + sec.padStart(2, "0"); } + +export function calculateCircleInfo(x1: number, y1: number, x2: number, y2: number, radius: number) { + // 计算P1到P2的中点 + const xm = (x1 + x2) / 2; + const ym = (y1 + y2) / 2; + + // P1到P2的距离的一半 + const dx = x2 - x1; + const dy = y2 - y1; + const d = Math.sqrt(dx * dx + dy * dy) / 2; + + // 如果距离大于直径,则无法形成圆 + if (d > radius) { + throw new Error("Given points are too far apart for the given radius."); + } + + // 计算垂直平分线的方向向量 + const len = Math.sqrt(radius * radius - d * d); + const nx = dy / (2 * d); + const ny = -dx / (2 * d); + + // 计算两个可能的圆心 + const cx1 = xm + nx * len; + const cy1 = ym + ny * len; + const cx2 = xm - nx * len; + const cy2 = ym - ny * len; + + // 使用atan2计算起始角和结束角 + function calculateAngle(cx: number, cy: number, px: number, py: number) { + return Math.atan2(py - cy, px - cx); + } + + const startAngle1 = calculateAngle(cx1, cy1, x1, y1); + const endAngle1 = calculateAngle(cx1, cy1, x2, y2); + const startAngle2 = calculateAngle(cx2, cy2, x1, y1); + const endAngle2 = calculateAngle(cx2, cy2, x2, y2); + + return [ + { center: { x: cx1, y: cy1 }, anglesForCenter: { startAngle: startAngle1, endAngle: endAngle1 } }, + { center: { x: cx2, y: cy2 }, anglesForCenter: { startAngle: startAngle2, endAngle: endAngle2 } }, + ]; +} + +export type CenterAndAngle = ReturnType; +export function calculateCircleBelow(x1: number, y1: number, x2: number, y2: number, radius: number) { + const results = calculateCircleInfo(x1, y1, x2, y2, radius); + if (results[0].center.y > results[1].center.y) { + return results[0]; + } else { + return results[1]; + } +} +export function calculateCircleAbove(x1: number, y1: number, x2: number, y2: number, radius: number) { + const results = calculateCircleInfo(x1, y1, x2, y2, radius); + if (results[0].center.y < results[1].center.y) { + return results[0]; + } else { + return results[1]; + } +} From 8a8bded26afc0fea7f21df64a6d081cd0928d251 Mon Sep 17 00:00:00 2001 From: zhangjiming Date: Wed, 5 Mar 2025 18:14:43 +0800 Subject: [PATCH 3/3] =?UTF-8?q?=E8=B0=83=E6=95=B4=E7=BD=91=E6=A0=BC?= =?UTF-8?q?=E7=BA=BF=EF=BC=8C=E5=A2=9E=E5=8A=A0=E5=8D=95=E4=BD=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/measure/components/MeasureAction.tsx | 4 +- src/pages/measure/components/graph/GridLayer.tsx | 77 ++++--- .../measure/components/graph/StandardLayer.tsx | 253 +++++++++++++-------- 3 files changed, 207 insertions(+), 127 deletions(-) diff --git a/src/pages/measure/components/MeasureAction.tsx b/src/pages/measure/components/MeasureAction.tsx index bd09e85..03abca2 100644 --- a/src/pages/measure/components/MeasureAction.tsx +++ b/src/pages/measure/components/MeasureAction.tsx @@ -20,9 +20,9 @@ export default function MeasureAction() { return (
- +
- +
diff --git a/src/pages/measure/components/graph/GridLayer.tsx b/src/pages/measure/components/graph/GridLayer.tsx index ed242e0..fb36c71 100644 --- a/src/pages/measure/components/graph/GridLayer.tsx +++ b/src/pages/measure/components/graph/GridLayer.tsx @@ -12,45 +12,62 @@ export default function GridLayer(props: { bottomPadding: number; columns: number; rows: number; - cellNum: number; + colCellNum: number; + rowCellNum: number; }) { const xStartPx = props.leftPadding; const xEndPx = props.width - props.rightPadding; const xStepPx = (props.width - props.leftPadding - props.rightPadding) / props.columns; - const xUnitPx = xStepPx / props.cellNum; + const xUnitPx = xStepPx / props.colCellNum; const yStartPx = props.topPadding; const yEndPx = props.height - props.bottomPadding; const yStepPx = (props.height - props.topPadding - props.bottomPadding) / props.rows; - const yUnitPx = yStepPx / props.cellNum; + const yUnitPx = yStepPx / props.rowCellNum; const canvasRef = useRef(null); - const drawGrid = useCallback((ctx: CanvasRenderingContext2D) => { - ctx.beginPath(); - ctx.strokeStyle = subLineColor; - for (let i = 1; i < props.columns * props.cellNum; ++i) { - if (i % props.cellNum === 0) continue; - ctx.moveTo(xStartPx + xUnitPx * i, yStartPx); - ctx.lineTo(xStartPx + xUnitPx * i, yEndPx); - } - for (let j = 1; j < props.rows * props.cellNum; ++j) { - if (j % props.cellNum === 0) continue; - ctx.moveTo(xStartPx, yStartPx + yUnitPx * j); - ctx.lineTo(xEndPx, yStartPx + yUnitPx * j); - } - ctx.stroke(); - - ctx.beginPath(); - ctx.strokeStyle = primaryLineColor; - for (let i = 0; i <= props.columns; ++i) { - ctx.moveTo(xStartPx + xStepPx * i, yStartPx); - ctx.lineTo(xStartPx + xStepPx * i, yEndPx); - } - for (let j = 0; j <= props.rows; ++j) { - ctx.moveTo(xStartPx, yStartPx + yStepPx * j); - ctx.lineTo(xEndPx, yStartPx + yStepPx * j); - } - ctx.stroke(); - },[props.cellNum, props.columns, props.rows, xEndPx, xStartPx, xStepPx, xUnitPx, yEndPx, yStartPx, yStepPx, yUnitPx]) + const drawGrid = useCallback( + (ctx: CanvasRenderingContext2D) => { + ctx.beginPath(); + ctx.strokeStyle = subLineColor; + for (let i = 1; i < props.columns * props.colCellNum; ++i) { + if (i % props.colCellNum === 0) continue; + ctx.moveTo(xStartPx + xUnitPx * i, yStartPx); + ctx.lineTo(xStartPx + xUnitPx * i, yEndPx); + } + for (let j = 1; j < props.rows * props.rowCellNum; ++j) { + if (j % props.rowCellNum === 0) continue; + ctx.moveTo(xStartPx, yStartPx + yUnitPx * j); + ctx.lineTo(xEndPx, yStartPx + yUnitPx * j); + } + ctx.stroke(); + + ctx.beginPath(); + ctx.strokeStyle = primaryLineColor; + for (let i = 0; i <= props.columns; ++i) { + ctx.moveTo(xStartPx + xStepPx * i, yStartPx); + ctx.lineTo(xStartPx + xStepPx * i, yEndPx); + } + for (let j = 0; j <= props.rows; ++j) { + ctx.moveTo(xStartPx, yStartPx + yStepPx * j); + ctx.lineTo(xEndPx, yStartPx + yStepPx * j); + } + ctx.stroke(); + }, + [ + props.colCellNum, + props.columns, + props.rowCellNum, + props.rows, + xEndPx, + xStartPx, + xStepPx, + xUnitPx, + yEndPx, + yStartPx, + yStepPx, + yUnitPx, + ] + ); useEffect(() => { // 获取canvas的2D绘图上下文 diff --git a/src/pages/measure/components/graph/StandardLayer.tsx b/src/pages/measure/components/graph/StandardLayer.tsx index fde7c9f..d6bed8f 100644 --- a/src/pages/measure/components/graph/StandardLayer.tsx +++ b/src/pages/measure/components/graph/StandardLayer.tsx @@ -31,104 +31,167 @@ export default function StandardLayer(props: { rightPadding: number; topPadding: number; bottomPadding: number; + columns: number; + rows: number; }) { + const xStartPx = props.leftPadding; + const xEndPx = props.width - props.rightPadding; + const xStepPx = (props.width - props.leftPadding - props.rightPadding) / props.columns; + const yStartPx = props.topPadding; + const yEndPx = props.height - props.bottomPadding; + const yStepPx = (props.height - props.topPadding - props.bottomPadding) / props.rows; + const canvasRef = useRef(null); - const draw = useCallback((ctx: CanvasRenderingContext2D) => { - // 使用context对象进行绘图 - ctx.fillStyle = "blue"; - ctx.strokeStyle = "blue"; - - ctx.translate(400, 100); - ctx.moveTo(-400, 0); - ctx.lineTo(400, 0); - ctx.moveTo(0, -100); - ctx.lineTo(0, 500); - ctx.stroke(); - - ctx.beginPath(); - ctx.strokeStyle = "red"; - // ---- 右侧 - let point0 = pointsRight[0]; - let point1 = pointsRight[1]; - ctx.moveTo(point0[0], point0[1]); - let param = calculateCircleBelow(point0[0], point0[1], point1[0], point1[1], 300 * unitPx); - console.log(param); - ctx.arc(param.center.x, param.center.y, 300 * unitPx, param.anglesForCenter.startAngle, param.anglesForCenter.endAngle); - - point0 = pointsRight[1]; - point1 = pointsRight[2]; - ctx.moveTo(point0[0], point0[1]); - param = calculateCircleBelow(point0[0], point0[1], point1[0], point1[1], 80 * unitPx); - console.log(param); - ctx.arc(param.center.x, param.center.y, 80 * unitPx, param.anglesForCenter.startAngle, param.anglesForCenter.endAngle); - - point0 = pointsRight[2]; - point1 = pointsRight[3]; - ctx.moveTo(point0[0], point0[1]); - param = calculateCircleBelow(point0[0], point0[1], point1[0], point1[1], 13 * unitPx); - console.log(param); - ctx.arc(param.center.x, param.center.y, 13 * unitPx, param.anglesForCenter.startAngle, param.anglesForCenter.endAngle); - - point0 = pointsRight[3]; - point1 = pointsRight[4]; - ctx.moveTo(point0[0], point0[1]); - ctx.lineTo(point1[0], point1[1]); - - point0 = pointsRight[4]; - point1 = pointsRight[5]; - ctx.moveTo(point0[0], point0[1]); - param = calculateCircleAbove(point0[0], point0[1], point1[0], point1[1], 5 * unitPx); - console.log(param); - ctx.arc(param.center.x, param.center.y, 5 * unitPx, param.anglesForCenter.startAngle, param.anglesForCenter.endAngle); - - point0 = pointsRight[5]; - point1 = pointsRight[6]; - ctx.moveTo(point0[0], point0[1]); - ctx.lineTo(point1[0], point1[1]); - - // ---- 左侧 - point0 = pointsLeft[0]; - point1 = pointsLeft[1]; - ctx.moveTo(point0[0], point0[1]); - ctx.lineTo(point1[0], point1[1]); - - point0 = pointsLeft[1]; - point1 = pointsLeft[2]; - ctx.moveTo(point0[0], point0[1]); - param = calculateCircleAbove(point0[0], point0[1], point1[0], point1[1], 5 * unitPx); - console.log(param); - ctx.arc(param.center.x, param.center.y, 5 * unitPx, param.anglesForCenter.startAngle, param.anglesForCenter.endAngle); - - point0 = pointsLeft[2]; - point1 = pointsLeft[3]; - ctx.moveTo(point0[0], point0[1]); - ctx.lineTo(point1[0], point1[1]); - - point0 = pointsLeft[3]; - point1 = pointsLeft[4]; - ctx.moveTo(point0[0], point0[1]); - param = calculateCircleBelow(point0[0], point0[1], point1[0], point1[1], 13 * unitPx); - console.log(param); - ctx.arc(param.center.x, param.center.y, 13 * unitPx, param.anglesForCenter.startAngle, param.anglesForCenter.endAngle); - - point0 = pointsLeft[4]; - point1 = pointsLeft[5]; - ctx.moveTo(point0[0], point0[1]); - param = calculateCircleBelow(point0[0], point0[1], point1[0], point1[1], 80 * unitPx); - console.log(param); - ctx.arc(param.center.x, param.center.y, 80 * unitPx, param.anglesForCenter.startAngle, param.anglesForCenter.endAngle); - - point0 = pointsLeft[5]; - point1 = pointsLeft[6]; - ctx.moveTo(point0[0], point0[1]); - param = calculateCircleBelow(point0[0], point0[1], point1[0], point1[1], 300 * unitPx); - console.log(param); - ctx.arc(param.center.x, param.center.y, 300 * unitPx, param.anglesForCenter.startAngle, param.anglesForCenter.endAngle); - - ctx.stroke(); - // ctx.fillRect(100, 100, 150, 100); // 绘制一个矩形 - }, []); + const draw = useCallback( + (ctx: CanvasRenderingContext2D) => { + ctx.strokeStyle = "#999"; + // 偏移原点 + const xOffset = (xEndPx - xStartPx) / 2; + const yOffset = yStepPx * 2; + const yMax = yEndPx - yStartPx - yOffset; + ctx.translate(xStartPx + xOffset, yStartPx + yOffset); + // 绘制原点交叉线 + ctx.moveTo(-xOffset, 0); + ctx.lineTo(xOffset, 0); + ctx.moveTo(0, -yOffset); + ctx.lineTo(0, yMax); + ctx.stroke(); + + // 绘制x轴y轴 单位数值 + ctx.beginPath(); + ctx.fillStyle = "#333333"; + ctx.textAlign = "center"; + ctx.font = "normal 14px system"; + for (let index = -4; index < 5; index++) { + ctx.fillText((index * 10).toString(), xStepPx * index, yMax + 20); + } + for (let index = -1; index < 5; index++) { + ctx.fillText((-index * 10).toString(), -xOffset - (index > 0 ? 18 : 14), yStepPx * index + 4); + } + + // 绘制标准线 + ctx.beginPath(); + ctx.strokeStyle = "red"; + // ---- 右侧 + let point0 = pointsRight[0]; + let point1 = pointsRight[1]; + ctx.moveTo(point0[0], point0[1]); + let param = calculateCircleBelow(point0[0], point0[1], point1[0], point1[1], 300 * unitPx); + console.log(param); + ctx.arc( + param.center.x, + param.center.y, + 300 * unitPx, + param.anglesForCenter.startAngle, + param.anglesForCenter.endAngle + ); + + point0 = pointsRight[1]; + point1 = pointsRight[2]; + ctx.moveTo(point0[0], point0[1]); + param = calculateCircleBelow(point0[0], point0[1], point1[0], point1[1], 80 * unitPx); + console.log(param); + ctx.arc( + param.center.x, + param.center.y, + 80 * unitPx, + param.anglesForCenter.startAngle, + param.anglesForCenter.endAngle + ); + + point0 = pointsRight[2]; + point1 = pointsRight[3]; + ctx.moveTo(point0[0], point0[1]); + param = calculateCircleBelow(point0[0], point0[1], point1[0], point1[1], 13 * unitPx); + console.log(param); + ctx.arc( + param.center.x, + param.center.y, + 13 * unitPx, + param.anglesForCenter.startAngle, + param.anglesForCenter.endAngle + ); + + point0 = pointsRight[3]; + point1 = pointsRight[4]; + ctx.moveTo(point0[0], point0[1]); + ctx.lineTo(point1[0], point1[1]); + + point0 = pointsRight[4]; + point1 = pointsRight[5]; + ctx.moveTo(point0[0], point0[1]); + param = calculateCircleAbove(point0[0], point0[1], point1[0], point1[1], 5 * unitPx); + console.log(param); + ctx.arc(param.center.x, param.center.y, 5 * unitPx, param.anglesForCenter.startAngle, param.anglesForCenter.endAngle); + + point0 = pointsRight[5]; + point1 = pointsRight[6]; + ctx.moveTo(point0[0], point0[1]); + ctx.lineTo(point1[0], point1[1]); + + // ---- 左侧 + point0 = pointsLeft[0]; + point1 = pointsLeft[1]; + ctx.moveTo(point0[0], point0[1]); + ctx.lineTo(point1[0], point1[1]); + + point0 = pointsLeft[1]; + point1 = pointsLeft[2]; + ctx.moveTo(point0[0], point0[1]); + param = calculateCircleAbove(point0[0], point0[1], point1[0], point1[1], 5 * unitPx); + console.log(param); + ctx.arc(param.center.x, param.center.y, 5 * unitPx, param.anglesForCenter.startAngle, param.anglesForCenter.endAngle); + + point0 = pointsLeft[2]; + point1 = pointsLeft[3]; + ctx.moveTo(point0[0], point0[1]); + ctx.lineTo(point1[0], point1[1]); + + point0 = pointsLeft[3]; + point1 = pointsLeft[4]; + ctx.moveTo(point0[0], point0[1]); + param = calculateCircleBelow(point0[0], point0[1], point1[0], point1[1], 13 * unitPx); + console.log(param); + ctx.arc( + param.center.x, + param.center.y, + 13 * unitPx, + param.anglesForCenter.startAngle, + param.anglesForCenter.endAngle + ); + + point0 = pointsLeft[4]; + point1 = pointsLeft[5]; + ctx.moveTo(point0[0], point0[1]); + param = calculateCircleBelow(point0[0], point0[1], point1[0], point1[1], 80 * unitPx); + console.log(param); + ctx.arc( + param.center.x, + param.center.y, + 80 * unitPx, + param.anglesForCenter.startAngle, + param.anglesForCenter.endAngle + ); + + point0 = pointsLeft[5]; + point1 = pointsLeft[6]; + ctx.moveTo(point0[0], point0[1]); + param = calculateCircleBelow(point0[0], point0[1], point1[0], point1[1], 300 * unitPx); + console.log(param); + ctx.arc( + param.center.x, + param.center.y, + 300 * unitPx, + param.anglesForCenter.startAngle, + param.anglesForCenter.endAngle + ); + + ctx.stroke(); + // ctx.fillRect(100, 100, 150, 100); // 绘制一个矩形 + }, + [xEndPx, xStartPx, xStepPx, yEndPx, yStartPx, yStepPx] + ); useEffect(() => { const canvas = canvasRef.current; if (!canvas) return;