Browse Source

添加角度标注层

feature/rail
zhangjiming 5 months ago
parent
commit
d9019713c6
  1. 13
      src/pages/measure/components/MeasureAction.tsx
  2. 109
      src/pages/measure/components/graph/MarkLayer.tsx
  3. 1
      src/pages/measure/components/graph/RealtimeLayer.tsx
  4. 49
      src/pages/measure/components/graph/StandardLayer.tsx
  5. 26
      src/utils/index.ts

13
src/pages/measure/components/MeasureAction.tsx

@ -6,6 +6,7 @@ import { createWebSocket, sharedWsUrl } from "../../../services/socket";
import GridLayer from "./graph/GridLayer";
import StandardLayer from "./graph/StandardLayer";
import RealtimeLayer from "./graph/RealtimeLayer";
import MarkLayer from "./graph/MarkLayer";
export default function MeasureAction() {
const navigate = useNavigate();
@ -78,6 +79,18 @@ export default function MeasureAction() {
rows={7}
/>
</div>
<div className="absolute top-0">
<MarkLayer
width={840}
height={600}
leftPadding={30}
rightPadding={10}
topPadding={10}
bottomPadding={30}
columns={10}
rows={7}
/>
</div>
</div>
<div className="w-[300px] flex-none py-6">
<h1 className="font-medium text-xl text-center"></h1>

109
src/pages/measure/components/graph/MarkLayer.tsx

@ -1,31 +1,88 @@
import { useCallback, useEffect, useRef } from "react";
import { calculatePointOnCircle, findSymmetricPoint } from "../../../../utils";
const marks = [
{ x: 9.949007022412, y: 0.1650166186941, degree: -80 },
{ x: 25.35, y: 2.184814802617, degree: -60 },
{ x: -9.949007022412, y: 0.1650166186941, degree: -100 },
{ x: -25.35, y: 2.184814802617, degree: -120 },
];
export default function MarkLayer(props: {
width: number;
height: number;
leftPadding: number;
rightPadding: number;
topPadding: number;
bottomPadding: number;
width: number;
height: number;
leftPadding: number;
rightPadding: number;
topPadding: number;
bottomPadding: number;
columns: number;
rows: number;
}) {
const canvasRef = useRef<HTMLCanvasElement | null>(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 (
<div>
<canvas ref={canvasRef} width={props.width} height={props.height}></canvas>
</div>
);
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 unitPx = xStepPx / 10;
const canvasRef = useRef<HTMLCanvasElement | null>(null);
const calcPoints = useCallback(
(arr: typeof marks) => {
return arr.map(p => {
const p1 = calculatePointOnCircle(p.x * unitPx, p.y * unitPx, xStepPx / 2, p.degree);
const p2 = findSymmetricPoint(p1.x, p1.y, p.x * unitPx, p.y * unitPx);
// 角度文本,向外偏移
const p3 = calculatePointOnCircle(p.x * unitPx, p.y * unitPx, xStepPx / 2 + 10, p.degree);
return [p1, p2, p3];
});
},
[unitPx, xStepPx]
);
const draw = useCallback(
(ctx: CanvasRenderingContext2D) => {
// 偏移原点
const xOffset = (xEndPx - xStartPx) / 2;
const yOffset = yStepPx * 2;
ctx.translate(xStartPx + xOffset, yStartPx + yOffset);
ctx.fillStyle = "#333333";
ctx.textAlign = "center";
ctx.font = "normal 14px system";
const lines = calcPoints(marks);
for (let idx = 0; idx < lines.length; idx++) {
const line = lines[idx];
ctx.moveTo(line[0].x, line[0].y);
ctx.lineTo(line[1].x, line[1].y);
ctx.save();
ctx.translate(line[2].x, line[2].y);
ctx.rotate(((marks[idx].degree + 90) * Math.PI) / 180);
ctx.fillText(`${-marks[idx].degree}°`, 0, 0);
ctx.restore();
}
ctx.stroke();
// ctx.fillStyle = "skyblue"; // 设置填充颜色
// ctx.fillRect(50, 50, 150, 100); // 绘制一个矩形
},
[calcPoints, xEndPx, xStartPx, yStartPx, yStepPx]
);
useEffect(() => {
const canvas = canvasRef.current;
if (!canvas) return;
const context = canvas.getContext("2d");
if (!context) return;
draw(context);
}, [draw]);
return (
<div>
<canvas ref={canvasRef} width={props.width} height={props.height}></canvas>
</div>
);
}

1
src/pages/measure/components/graph/RealtimeLayer.tsx

@ -72,7 +72,6 @@ export default function RealtimeLayer(props: {
// console.log(data.data);
// setRtPoints(rtPoints.concat([data.data]));
pointArr.push(data.data);
console.log(pointArr.length);
const canvas = canvasRef.current;
if (!canvas) return;

49
src/pages/measure/components/graph/StandardLayer.tsx

@ -73,44 +73,44 @@ export default function StandardLayer(props: {
// 绘制标准线
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);
// console.log(param);
ctx.arc(
param.center.x,
param.center.y,
300 * unitPx,
param.anglesForCenter.startAngle,
param.anglesForCenter.endAngle
param.angles.startAngle,
param.angles.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);
// console.log(param);
ctx.arc(
param.center.x,
param.center.y,
80 * unitPx,
param.anglesForCenter.startAngle,
param.anglesForCenter.endAngle
param.angles.startAngle,
param.angles.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);
// console.log(param);
ctx.arc(
param.center.x,
param.center.y,
13 * unitPx,
param.anglesForCenter.startAngle,
param.anglesForCenter.endAngle
param.angles.startAngle,
param.angles.endAngle
);
point0 = pointsRight[3];
@ -122,15 +122,15 @@ export default function StandardLayer(props: {
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);
// console.log(param);
ctx.arc(param.center.x, param.center.y, 5 * unitPx, param.angles.startAngle, param.angles.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]);
@ -140,8 +140,8 @@ export default function StandardLayer(props: {
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);
// console.log(param);
ctx.arc(param.center.x, param.center.y, 5 * unitPx, param.angles.startAngle, param.angles.endAngle);
point0 = pointsLeft[2];
point1 = pointsLeft[3];
@ -152,43 +152,42 @@ export default function StandardLayer(props: {
point1 = pointsLeft[4];
ctx.moveTo(point0[0], point0[1]);
param = calculateCircleBelow(point0[0], point0[1], point1[0], point1[1], 13 * unitPx);
console.log(param);
// console.log(param);
ctx.arc(
param.center.x,
param.center.y,
13 * unitPx,
param.anglesForCenter.startAngle,
param.anglesForCenter.endAngle
param.angles.startAngle,
param.angles.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);
// console.log(param);
ctx.arc(
param.center.x,
param.center.y,
80 * unitPx,
param.anglesForCenter.startAngle,
param.anglesForCenter.endAngle
param.angles.startAngle,
param.angles.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);
// console.log(param);
ctx.arc(
param.center.x,
param.center.y,
300 * unitPx,
param.anglesForCenter.startAngle,
param.anglesForCenter.endAngle
param.angles.startAngle,
param.angles.endAngle
);
ctx.stroke();
// ctx.fillRect(100, 100, 150, 100); // 绘制一个矩形
},
[pointsLeft, pointsRight, unitPx, xEndPx, xStartPx, xStepPx, yEndPx, yStartPx, yStepPx]
);

26
src/utils/index.ts

@ -4,6 +4,7 @@ export function formatRemainTime(seconds: number) {
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;
@ -41,12 +42,13 @@ export function calculateCircleInfo(x1: number, y1: number, x2: number, y2: numb
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 } },
{ center: { x: cx1, y: cy1 }, angles: { startAngle: startAngle1, endAngle: endAngle1 } },
{ center: { x: cx2, y: cy2 }, angles: { startAngle: startAngle2, endAngle: endAngle2 } },
];
}
export type CenterAndAngle = ReturnType<typeof calculateCircleBelow>;
// 取圆心偏下的那一组圆心和夹角
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) {
@ -55,6 +57,7 @@ export function calculateCircleBelow(x1: number, y1: number, x2: number, y2: num
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) {
@ -63,3 +66,22 @@ export function calculateCircleAbove(x1: number, y1: number, x2: number, y2: num
return results[1];
}
}
// 根据圆心坐标、半径和角度来计算目标点的坐标
export function calculatePointOnCircle(cx: number, cy: number, radius: number, angleInDegrees: number) {
// 将角度从度转换为弧度
const angleInRadians = angleInDegrees * (Math.PI / 180);
// 计算目标点的坐标
const x = cx + radius * Math.cos(angleInRadians);
const y = cy + radius * Math.sin(angleInRadians);
return { x, y };
}
// 计算一个点相对于原点的对称点坐标
export function findSymmetricPoint(px: number, py: number, ox = 0, oy = 0) {
// 计算对称点的坐标
const sx = 2 * ox - px;
const sy = 2 * oy - py;
return { x: sx, y: sy };
}
Loading…
Cancel
Save